|
|
1.1 root 1: /*
2: Hatari - main.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: Main initialization and event handling routines.
8: */
9: const char Main_fileid[] = "Hatari main.c : " __DATE__ " " __TIME__;
10:
11: #include <time.h>
1.1.1.2 root 12: #include <errno.h>
1.1 root 13: #include <SDL.h>
14:
15: #include "main.h"
16: #include "configuration.h"
17: #include "control.h"
18: #include "options.h"
19: #include "dialog.h"
20: #include "ioMem.h"
1.1.1.2 root 21: #include "keymap.h"
1.1 root 22: #include "log.h"
23: #include "m68000.h"
24: #include "memorySnapShot.h"
25: #include "paths.h"
26: #include "reset.h"
1.1.1.2 root 27: #include "resolution.h"
1.1 root 28: #include "screen.h"
29: #include "sdlgui.h"
30: #include "shortcut.h"
31: #include "statusbar.h"
32: #include "nextMemory.h"
33: #include "str.h"
34: #include "video.h"
1.1.1.5 ! root 35: #include "audio.h"
1.1 root 36: #include "avi_record.h"
37: #include "debugui.h"
1.1.1.2 root 38: #include "clocks_timings.h"
1.1.1.4 root 39: #include "file.h"
1.1.1.5 ! root 40: #include "dsp.h"
1.1.1.2 root 41:
1.1 root 42: #include "hatari-glue.h"
43:
1.1.1.2 root 44: #if HAVE_GETTIMEOFDAY
45: #include <sys/time.h>
46: #endif
1.1 root 47:
1.1.1.4 root 48: int nFrameSkips;
1.1 root 49:
50: bool bQuitProgram = false; /* Flag to quit program cleanly */
51:
1.1.1.2 root 52: static Uint32 nRunVBLs; /* Whether and how many VBLS to run before exit */
1.1 root 53: static Uint32 nFirstMilliTick; /* Ticks when VBL counting started */
54: static Uint32 nVBLCount; /* Frame count */
55:
56: static bool bEmulationActive = true; /* Run emulation when started */
57: static bool bAccurateDelays; /* Host system has an accurate SDL_Delay()? */
58: static bool bIgnoreNextMouseMotion = false; /* Next mouse motion will be ignored (needed after SDL_WarpMouse) */
59:
60:
61: /*-----------------------------------------------------------------------*/
62: /**
63: * Return current time as millisecond for performance measurements.
64: *
65: * (On Unix only time spent by Hatari itself is counted, on other
66: * platforms less accurate SDL "wall clock".)
67: */
68: #if HAVE_SYS_TIMES_H
69: #include <unistd.h>
70: #include <sys/times.h>
71: static Uint32 Main_GetTicks(void)
72: {
73: static unsigned int ticks_to_msec = 0;
74: struct tms fields;
75: if (!ticks_to_msec)
76: {
77: ticks_to_msec = sysconf(_SC_CLK_TCK);
78: printf("OS clock ticks / second: %d\n", ticks_to_msec);
79: /* Linux has 100Hz virtual clock so no accuracy loss there */
80: ticks_to_msec = 1000UL / ticks_to_msec;
81: }
82: /* return milliseconds (clock ticks) spent in this process
83: */
84: times(&fields);
85: return ticks_to_msec * fields.tms_utime;
86: }
87: #else
88: # warning "times() function missing, using inaccurate SDL_GetTicks() instead."
89: # define Main_GetTicks SDL_GetTicks
90: #endif
91:
92:
1.1.1.2 root 93: //#undef HAVE_GETTIMEOFDAY
94: //#undef HAVE_NANOSLEEP
95:
96: /*-----------------------------------------------------------------------*/
97: /**
98: * Return a time counter in micro seconds.
99: * If gettimeofday is available, we use it directly, else we convert the
100: * return of SDL_GetTicks in micro sec.
101: */
102:
103: static Sint64 Time_GetTicks ( void )
104: {
105: Sint64 ticks_micro;
106:
107: #if HAVE_GETTIMEOFDAY
108: struct timeval now;
109: gettimeofday ( &now , NULL );
110: ticks_micro = (Sint64)now.tv_sec * 1000000 + now.tv_usec;
111: #else
112: ticks_micro = (Sint64)SDL_GetTicks() * 1000; /* milli sec -> micro sec */
113: #endif
114:
115: return ticks_micro;
116: }
117:
118:
119: /*-----------------------------------------------------------------------*/
120: /**
121: * Sleep for a given number of micro seconds.
122: * If nanosleep is available, we use it directly, else we use SDL_Delay
123: * (which is portable, but less accurate as is uses milli-seconds)
124: */
125:
126: static void Time_Delay ( Sint64 ticks_micro )
127: {
128: #if HAVE_NANOSLEEP
129: struct timespec ts;
130: int ret;
131: ts.tv_sec = ticks_micro / 1000000;
132: ts.tv_nsec = (ticks_micro % 1000000) * 1000; /* micro sec -> nano sec */
133: /* wait until all the delay is elapsed, including possible interruptions by signals */
134: do
135: {
136: errno = 0;
137: ret = nanosleep(&ts, &ts);
138: } while ( ret && ( errno == EINTR ) ); /* keep on sleeping if we were interrupted */
139: #else
140: SDL_Delay ( (Uint32)(ticks_micro / 1000) ) ; /* micro sec -> milli sec */
141: #endif
142: }
143:
144:
1.1 root 145: /*-----------------------------------------------------------------------*/
146: /**
147: * Pause emulation, stop sound. 'visualize' should be set true,
148: * unless unpause will be called immediately afterwards.
149: *
150: * @return true if paused now, false if was already paused
151: */
152: bool Main_PauseEmulation(bool visualize)
153: {
154: if ( !bEmulationActive )
155: return false;
156:
1.1.1.5 ! root 157: //Audio_Output_Enable(false);
1.1 root 158: bEmulationActive = false;
159: if (visualize)
160: {
161: if (nFirstMilliTick)
162: {
163: int interval = Main_GetTicks() - nFirstMilliTick;
164: static float previous;
165: float current;
166:
167: current = (1000.0 * nVBLCount) / interval;
168: printf("SPEED: %.1f VBL/s (%d/%.1fs), diff=%.1f%%\n",
169: current, nVBLCount, interval/1000.0,
1.1.1.2 root 170: previous>0.0 ? 100*(current-previous)/previous : 0.0);
1.1 root 171: nVBLCount = nFirstMilliTick = 0;
172: previous = current;
173: }
174:
175: Statusbar_AddMessage("Emulation paused", 100);
176: /* make sure msg gets shown */
177: Statusbar_Update(sdlscrn);
178:
1.1.1.5 ! root 179: if (bGrabMouse && !bInFullScreen) {
1.1 root 180: /* Un-grab mouse pointer in windowed mode */
1.1.1.5 ! root 181: SDL_SetRelativeMouseMode(SDL_FALSE);
! 182: SDL_SetWindowGrab(sdlWindow, SDL_FALSE);
! 183: }
1.1 root 184: }
185: return true;
186: }
187:
188: /*-----------------------------------------------------------------------*/
189: /**
190: * Start/continue emulation
191: *
192: * @return true if continued, false if was already running
193: */
194: bool Main_UnPauseEmulation(void)
195: {
196: if ( bEmulationActive )
197: return false;
198:
1.1.1.5 ! root 199: //Audio_Output_Enable(ConfigureParams.Sound.bEnableSound);
1.1 root 200: bEmulationActive = true;
201:
202: /* Cause full screen update (to clear all) */
203: Screen_SetFullUpdate();
204:
1.1.1.5 ! root 205: if (bGrabMouse) {
1.1 root 206: /* Grab mouse pointer again */
1.1.1.5 ! root 207: SDL_SetRelativeMouseMode(SDL_TRUE);
! 208: SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
! 209: }
1.1 root 210: return true;
211: }
212:
213: /*-----------------------------------------------------------------------*/
214: /**
215: * Optionally ask user whether to quit and set bQuitProgram accordingly
216: */
217: void Main_RequestQuit(void)
218: {
219: if (ConfigureParams.Memory.bAutoSave)
220: {
221: bQuitProgram = true;
222: MemorySnapShot_Capture(ConfigureParams.Memory.szAutoSaveFileName, false);
223: }
224: else if (ConfigureParams.Log.bConfirmQuit)
225: {
226: bQuitProgram = false; /* if set true, dialog exits */
227: bQuitProgram = DlgAlert_Query("All unsaved data will be lost.\nDo you really want to quit?");
228: }
229: else
230: {
231: bQuitProgram = true;
232: }
233:
234: if (bQuitProgram)
235: {
236: /* Assure that CPU core shuts down */
237: M68000_SetSpecial(SPCFLAG_BRK);
238: }
239: }
240:
241: /*-----------------------------------------------------------------------*/
242: /**
1.1.1.2 root 243: * Set how many VBLs Hatari should run, from the moment this function
244: * is called.
245: */
246: void Main_SetRunVBLs(Uint32 vbls)
247: {
248: fprintf(stderr, "Exit after %d VBLs.\n", vbls);
249: nRunVBLs = vbls;
250: nVBLCount = 0;
251: }
252:
253: /*-----------------------------------------------------------------------*/
254: /**
1.1 root 255: * This function waits on each emulated VBL to synchronize the real time
256: * with the emulated ST.
257: * Unfortunately SDL_Delay and other sleep functions like usleep or nanosleep
258: * are very inaccurate on some systems like Linux 2.4 or Mac OS X (they can only
259: * wait for a multiple of 10ms due to the scheduler on these systems), so we have
260: * to "busy wait" there to get an accurate timing.
1.1.1.2 root 261: * All times are expressed as micro seconds, to avoid too much rounding error.
1.1 root 262: */
263: void Main_WaitOnVbl(void)
264: {
1.1.1.2 root 265: Sint64 CurrentTicks;
266: static Sint64 DestTicks = 0;
267: Sint64 FrameDuration_micro;
268: Sint64 nDelay;
1.1 root 269:
270: nVBLCount++;
271: if (nRunVBLs && nVBLCount >= nRunVBLs)
272: {
273: /* show VBLs/s */
274: Main_PauseEmulation(true);
275: exit(0);
276: }
277:
1.1.1.2 root 278: // FrameDuration_micro = (Sint64) ( 1000000.0 / nScreenRefreshRate + 0.5 ); /* round to closest integer */
1.1.1.4 root 279: FrameDuration_micro = ClocksTimings_GetVBLDuration_micro ( ConfigureParams.System.nMachineType , 68 );
280: // FrameDuration_micro = 1000000/50;
1.1.1.2 root 281: CurrentTicks = Time_GetTicks();
282:
283: if ( DestTicks == 0 ) /* first call, init DestTicks */
1.1.1.5 ! root 284: {
1.1.1.2 root 285: DestTicks = CurrentTicks + FrameDuration_micro;
1.1.1.5 ! root 286: }
1.1.1.2 root 287:
288: nDelay = DestTicks - CurrentTicks;
1.1 root 289:
290: /* Do not wait if we are in fast forward mode or if we are totally out of sync */
291: if (ConfigureParams.System.bFastForward == true
1.1.1.5 ! root 292: || nDelay < -4*FrameDuration_micro || nDelay > 50*FrameDuration_micro)
1.1 root 293: {
294: if (ConfigureParams.System.bFastForward == true)
295: {
296: if (!nFirstMilliTick)
297: nFirstMilliTick = Main_GetTicks();
298: }
1.1.1.4 root 299: if (nFrameSkips < ConfigureParams.Screen.nFrameSkips)
300: {
301: nFrameSkips += 1;
302: Log_Printf(LOG_DEBUG, "Increased frameskip to %d\n", nFrameSkips);
303: }
1.1.1.2 root 304: /* Only update DestTicks for next VBL */
305: DestTicks = CurrentTicks + FrameDuration_micro;
1.1 root 306: return;
307: }
308: /* If automatic frameskip is enabled and delay's more than twice
309: * the effect of single frameskip, decrease frameskip
310: */
1.1.1.4 root 311: if (nFrameSkips > 0
312: && ConfigureParams.Screen.nFrameSkips >= AUTO_FRAMESKIP_LIMIT
313: && 2*nDelay > FrameDuration_micro/nFrameSkips)
314: {
315: nFrameSkips -= 1;
316: Log_Printf(LOG_DEBUG, "Decreased frameskip to %d\n", nFrameSkips);
317: }
1.1 root 318:
319: if (bAccurateDelays)
320: {
321: /* Accurate sleeping is possible -> use SDL_Delay to free the CPU */
1.1.1.2 root 322: if (nDelay > 1000)
323: Time_Delay(nDelay - 1000);
1.1 root 324: }
325: else
326: {
327: /* No accurate SDL_Delay -> only wait if more than 5ms to go... */
1.1.1.2 root 328: if (nDelay > 5000)
329: Time_Delay(nDelay<10000 ? nDelay-1000 : 9000);
1.1 root 330: }
331:
332: /* Now busy-wait for the right tick: */
333: while (nDelay > 0)
334: {
1.1.1.2 root 335: CurrentTicks = Time_GetTicks();
336: nDelay = DestTicks - CurrentTicks;
1.1.1.5 ! root 337: /* If the delay is still bigger than one frame, somebody
! 338: * played tricks with the system clock and we have to abort */
! 339: if (nDelay > FrameDuration_micro)
! 340: break;
1.1 root 341: }
342:
1.1.1.2 root 343: //printf ( "tick %lld\n" , CurrentTicks );
344: /* Update DestTicks for next VBL */
345: DestTicks += FrameDuration_micro;
1.1 root 346: }
347:
348:
349: /*-----------------------------------------------------------------------*/
350: /**
351: * Since SDL_Delay and friends are very inaccurate on some systems, we have
352: * to check if we can rely on this delay function.
353: */
354: static void Main_CheckForAccurateDelays(void)
355: {
356: int nStartTicks, nEndTicks;
357:
358: /* Force a task switch now, so we have a longer timeslice afterwards */
359: SDL_Delay(10);
360:
361: nStartTicks = SDL_GetTicks();
362: SDL_Delay(1);
363: nEndTicks = SDL_GetTicks();
364:
365: /* If the delay took longer than 10ms, we are on an inaccurate system! */
366: bAccurateDelays = ((nEndTicks - nStartTicks) < 9);
367:
368: if (bAccurateDelays)
369: Log_Printf(LOG_WARN, "Host system has accurate delays. (%d)\n", nEndTicks - nStartTicks);
370: else
371: Log_Printf(LOG_WARN, "Host system does not have accurate delays. (%d)\n", nEndTicks - nStartTicks);
372: }
373:
374:
375: /* ----------------------------------------------------------------------- */
376: /**
377: * Set mouse pointer to new coordinates and set flag to ignore the mouse event
378: * that is generated by SDL_WarpMouse().
379: */
380: void Main_WarpMouse(int x, int y)
381: {
1.1.1.5 ! root 382: SDL_WarpMouseInWindow(sdlWindow, x, y); /* Set mouse pointer to new position */
! 383: bIgnoreNextMouseMotion = true; /* Ignore mouse motion event from SDL_WarpMouse */
1.1 root 384: }
385:
386:
387: /* ----------------------------------------------------------------------- */
388: /**
389: * Handle mouse motion event.
390: */
1.1.1.5 ! root 391: SDL_Event mymouse[100];
1.1 root 392: static void Main_HandleMouseMotion(SDL_Event *pEvent)
393: {
394: int dx, dy;
1.1.1.5 ! root 395: int i,nb;
1.1 root 396:
397: dx = pEvent->motion.xrel;
398: dy = pEvent->motion.yrel;
399:
1.1.1.5 ! root 400: /* get all mouse event to clean the queue and sum them */
! 401: nb=SDL_PeepEvents(&mymouse[0], 100, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION);
! 402:
! 403: for (i=0;i<nb;i++) {
! 404: dx += mymouse[i].motion.xrel;
! 405: dy += mymouse[i].motion.yrel;
1.1 root 406: }
407:
1.1.1.5 ! root 408: if (bGrabMouse) {
! 409: Keymap_MouseMove(dx,dy,ConfigureParams.Mouse.fLinSpeedLocked,ConfigureParams.Mouse.fExpSpeedLocked);
! 410: } else {
! 411: Keymap_MouseMove(dx,dy,ConfigureParams.Mouse.fLinSpeedNormal,ConfigureParams.Mouse.fLinSpeedNormal);
! 412: }
1.1 root 413: }
414:
415:
416: /* ----------------------------------------------------------------------- */
417: /**
418: * SDL message handler.
419: * Here we process the SDL events (keyboard, mouse, ...) and map it to
420: * Atari IKBD events.
421: */
422: void Main_EventHandler(void)
423: {
424: bool bContinueProcessing;
425: SDL_Event event;
426: int events;
427: int remotepause;
428:
429: do
430: {
431: bContinueProcessing = false;
432:
433: /* check remote process control */
434: remotepause = Control_CheckUpdates();
435:
436: if ( bEmulationActive || remotepause )
437: {
438: events = SDL_PollEvent(&event);
439: }
440: else
441: {
442: ShortCut_ActKey();
443: /* last (shortcut) event activated emulation? */
444: if ( bEmulationActive )
445: break;
446: events = SDL_WaitEvent(&event);
447: }
448: if (!events)
449: {
450: /* no events -> if emulation is active or
451: * user is quitting -> return from function.
452: */
453: continue;
454: }
455: switch (event.type)
456: {
1.1.1.5 ! root 457: case SDL_WINDOWEVENT:
! 458: if(event.window.event == SDL_WINDOWEVENT_CLOSE)
! 459: Main_RequestQuit();
! 460: break;
1.1 root 461: case SDL_QUIT:
462: Main_RequestQuit();
463: break;
464:
465: case SDL_MOUSEMOTION: /* Read/Update internal mouse position */
466: Main_HandleMouseMotion(&event);
1.1.1.5 ! root 467: bContinueProcessing = false;
1.1 root 468: break;
469:
470: case SDL_MOUSEBUTTONDOWN:
471: if (event.button.button == SDL_BUTTON_LEFT)
472: {
1.1.1.5 ! root 473: if (ConfigureParams.Mouse.bEnableAutoGrab && !bGrabMouse) {
! 474: bGrabMouse = true; /* Toggle flag */
! 475:
! 476: /* If we are in windowed mode, toggle the mouse cursor mode now: */
! 477: if (!bInFullScreen)
! 478: {
! 479: SDL_SetRelativeMouseMode(SDL_TRUE);
! 480: SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
! 481: Main_SetTitle(MOUSE_LOCK_MSG);
! 482: }
! 483: }
! 484:
! 485: Keymap_MouseDown(true);
1.1 root 486: }
487: else if (event.button.button == SDL_BUTTON_RIGHT)
488: {
1.1.1.5 ! root 489: Keymap_MouseDown(false);
1.1.1.2 root 490: // Keyboard.bRButtonDown |= BUTTON_MOUSE;
1.1 root 491: }
492: else if (event.button.button == SDL_BUTTON_MIDDLE)
493: {
1.1.1.2 root 494: /* Start double-click sequence in emulation time */
495: // Keyboard.LButtonDblClk = 1;
1.1 root 496: }
497: break;
498:
499: case SDL_MOUSEBUTTONUP:
500: if (event.button.button == SDL_BUTTON_LEFT)
501: {
1.1.1.5 ! root 502: Keymap_MouseUp(true);
1.1.1.2 root 503: // Keyboard.bLButtonDown &= ~BUTTON_MOUSE;
1.1 root 504: }
505: else if (event.button.button == SDL_BUTTON_RIGHT)
506: {
1.1.1.5 ! root 507: Keymap_MouseUp(false);
1.1.1.2 root 508: // Keyboard.bRButtonDown &= ~BUTTON_MOUSE;
1.1 root 509: }
510: break;
511:
512: case SDL_KEYDOWN:
1.1.1.5 ! root 513: if (ConfigureParams.Keyboard.bDisableKeyRepeat && event.key.repeat)
! 514: break;
! 515:
! 516: Keymap_KeyDown(&event.key.keysym);
1.1 root 517: break;
518:
519: case SDL_KEYUP:
1.1.1.5 ! root 520: Keymap_KeyUp(&event.key.keysym);
1.1 root 521: break;
1.1.1.5 ! root 522:
1.1 root 523:
524: default:
525: /* don't let unknown events delay event processing */
526: bContinueProcessing = true;
527: break;
528: }
529: } while (bContinueProcessing || !(bEmulationActive || bQuitProgram));
530: }
531:
532:
533: /*-----------------------------------------------------------------------*/
534: /**
1.1.1.2 root 535: * Set Hatari window title. Use NULL for default
536: */
537: void Main_SetTitle(const char *title)
538: {
1.1.1.5 ! root 539: if (title)
! 540: SDL_SetWindowTitle(sdlWindow, title);
! 541: else
! 542: SDL_SetWindowTitle(sdlWindow, PROG_NAME);
1.1.1.2 root 543: }
544:
545: /*-----------------------------------------------------------------------*/
546: /**
1.1 root 547: * Initialise emulation
548: */
549: static void Main_Init(void)
550: {
551: /* Open debug log file */
552: if (!Log_Init())
553: {
554: fprintf(stderr, "Logging/tracing initialization failed\n");
555: exit(-1);
556: }
557: Log_Printf(LOG_INFO, PROG_NAME ", compiled on: " __DATE__ ", " __TIME__ "\n");
558:
559: /* Init SDL's video subsystem. Note: Audio and joystick subsystems
560: will be initialized later (failures there are not fatal). */
561: if (SDL_Init(SDL_INIT_VIDEO | Opt_GetNoParachuteFlag()) < 0)
562: {
563: fprintf(stderr, "Could not initialize the SDL library:\n %s\n", SDL_GetError() );
564: exit(-1);
565: }
1.1.1.2 root 566: ClocksTimings_InitMachine ( ConfigureParams.System.nMachineType );
567: Resolution_Init();
1.1 root 568: SDLGui_Init();
569: Screen_Init();
1.1.1.2 root 570: Main_SetTitle(NULL);
571: // HostScreen_Init();
1.1.1.5 ! root 572: DSP_Init();
1.1.1.2 root 573: // Floppy_Init();
1.1 root 574: M68000_Init(); /* Init CPU emulation */
1.1.1.2 root 575: // Audio_Init();
576: // DmaSnd_Init();
1.1.1.3 root 577: Keymap_Init();
1.1.1.2 root 578:
1.1.1.4 root 579:
1.1.1.2 root 580: /* call menu at startup */
1.1.1.4 root 581: if (!File_Exists(sConfigFileName) || ConfigureParams.ConfigDialog.bShowConfigDialogAtStartup)
582: Dialog_DoProperty();
583: else
584: Dialog_CheckFiles();
585:
1.1.1.2 root 586: if (bQuitProgram)
1.1.1.4 root 587: {
588: SDL_Quit();
589: exit(-2);
590: }
591:
592:
593: // const char *err_msg;
594: //
595: // while ((err_msg=Reset_Cold())!=NULL)
596: // {
597: // DlgMissing_Rom();
598: // if (bQuitProgram) {
599: // Main_RequestQuit();
600: // break;
601: // }
602: // }
603:
604: Reset_Cold();
605:
606: // if (bQuitProgram) {
607: // SDL_Quit();
608: // exit(-2);
609: // }
1.1 root 610: IoMem_Init();
611:
612: /* done as last, needs CPU & DSP running... */
613: DebugUI_Init();
614: }
615:
616:
617: /*-----------------------------------------------------------------------*/
618: /**
619: * Un-Initialise emulation
620: */
621: static void Main_UnInit(void)
622: {
623: Screen_ReturnFromFullScreen();
624: IoMem_UnInit();
625: SDLGui_UnInit();
626: Screen_UnInit();
627: Exit680x0();
628:
629: /* SDL uninit: */
630: SDL_Quit();
631:
632: /* Close debug log file */
633: Log_UnInit();
634: }
635:
636:
637: /*-----------------------------------------------------------------------*/
638: /**
639: * Load initial configuration file(s)
640: */
641: static void Main_LoadInitialConfig(void)
642: {
643: char *psGlobalConfig;
644:
645: psGlobalConfig = malloc(FILENAME_MAX);
646: if (psGlobalConfig)
647: {
648: #if defined(__AMIGAOS4__)
649: strncpy(psGlobalConfig, CONFDIR"previous.cfg", FILENAME_MAX);
650: #else
651: snprintf(psGlobalConfig, FILENAME_MAX, CONFDIR"%cprevious.cfg", PATHSEP);
652: #endif
653: /* Try to load the global configuration file */
654: Configuration_Load(psGlobalConfig);
655:
656: free(psGlobalConfig);
657: }
658:
659: /* Now try the users configuration file */
660: Configuration_Load(NULL);
661: }
662:
663: /*-----------------------------------------------------------------------*/
664: /**
665: * Set TOS etc information and initial help message
666: */
667: static void Main_StatusbarSetup(void)
668: {
669: const char *name = NULL;
1.1.1.5 ! root 670: SDL_Keycode key;
1.1 root 671:
672: key = ConfigureParams.Shortcut.withoutModifier[SHORTCUT_OPTIONS];
673: if (!key)
674: key = ConfigureParams.Shortcut.withModifier[SHORTCUT_OPTIONS];
675: if (key)
676: name = SDL_GetKeyName(key);
677: if (name)
678: {
679: char message[24], *keyname;
680: #ifdef _MUDFLAP
681: __mf_register(name, 32, __MF_TYPE_GUESS, "SDL keyname");
682: #endif
683: keyname = Str_ToUpper(strdup(name));
684: snprintf(message, sizeof(message), "Press %s for Options", keyname);
685: free(keyname);
686:
687: Statusbar_AddMessage(message, 6000);
688: }
689: /* update information loaded by Main_Init() */
690: Statusbar_UpdateInfo();
691: }
692:
693: /*-----------------------------------------------------------------------*/
694: /**
695: * Main
696: *
697: * Note: 'argv' cannot be declared const, MinGW would then fail to link.
698: */
699: int main(int argc, char *argv[])
700: {
701: /* Generate random seed */
702: srand(time(NULL));
703:
704: /* Initialize directory strings */
705: Paths_Init(argv[0]);
706:
707: /* Set default configuration values: */
708: Configuration_SetDefault();
709:
710: /* Now load the values from the configuration file */
711: Main_LoadInitialConfig();
1.1.1.5 ! root 712:
! 713: #if 0 /* FIXME: This sometimes causes exits when starting from application bundles */
1.1 root 714: /* Check for any passed parameters */
1.1.1.2 root 715: if (!Opt_ParseParameters(argc, (const char * const *)argv))
1.1 root 716: {
717: return 1;
718: }
1.1.1.5 ! root 719: #endif
1.1 root 720: /* monitor type option might require "reset" -> true */
721: Configuration_Apply(true);
722:
723: #ifdef WIN32
724: Win_OpenCon();
725: #endif
726:
727: /* Needed on maemo but useful also with normal X11 window managers
728: * for window grouping when you have multiple Hatari SDL windows open
729: */
730: #if HAVE_SETENV
731: setenv("SDL_VIDEO_X11_WMCLASS", "previous", 1);
732: #endif
733:
734: /* Init emulator system */
735: Main_Init();
736:
737: /* Set initial Statusbar information */
738: Main_StatusbarSetup();
739:
740: /* Check if SDL_Delay is accurate */
741: Main_CheckForAccurateDelays();
742:
743:
744: /* Run emulation */
745: Main_UnPauseEmulation();
746: M68000_Start(); /* Start emulation */
747:
1.1.1.4 root 748:
1.1 root 749: /* Un-init emulation system */
750: Main_UnInit();
751:
752: return 0;
753: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.