|
|
1.1 root 1: /*
1.1.1.6 root 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.
1.1 root 8: */
1.1.1.17! root 9: const char Main_fileid[] = "Hatari main.c : " __DATE__ " " __TIME__;
1.1 root 10:
1.1.1.13 root 11: #include <time.h>
1.1 root 12: #include <SDL.h>
13:
14: #include "main.h"
15: #include "configuration.h"
1.1.1.15 root 16: #include "control.h"
1.1.1.12 root 17: #include "options.h"
1.1 root 18: #include "dialog.h"
19: #include "audio.h"
20: #include "joy.h"
21: #include "floppy.h"
22: #include "gemdos.h"
1.1.1.4 root 23: #include "hdc.h"
1.1.1.16 root 24: #include "ide.h"
1.1 root 25: #include "ikbd.h"
1.1.1.10 root 26: #include "ioMem.h"
1.1.1.5 root 27: #include "keymap.h"
1.1.1.10 root 28: #include "log.h"
1.1 root 29: #include "m68000.h"
30: #include "memorySnapShot.h"
1.1.1.8 root 31: #include "midi.h"
1.1.1.13 root 32: #include "nvram.h"
33: #include "paths.h"
1.1 root 34: #include "printer.h"
1.1.1.8 root 35: #include "reset.h"
1.1 root 36: #include "rs232.h"
37: #include "screen.h"
1.1.1.5 root 38: #include "sdlgui.h"
1.1 root 39: #include "shortcut.h"
40: #include "sound.h"
1.1.1.15 root 41: #include "statusbar.h"
1.1.1.8 root 42: #include "stMemory.h"
1.1.1.15 root 43: #include "str.h"
1.1 root 44: #include "tos.h"
45: #include "video.h"
46:
1.1.1.13 root 47: #include "hatari-glue.h"
48:
49: #include "falcon/hostscreen.h"
50: #if ENABLE_DSP_EMU
51: #include "falcon/dsp.h"
52: #endif
1.1 root 53:
54:
1.1.1.17! root 55: bool bQuitProgram = false; /* Flag to quit program cleanly */
1.1.1.13 root 56:
1.1.1.17! root 57: Uint32 nRunVBLs; /* Whether and how many VBLS to run before exit */
! 58: static Uint32 nFirstMilliTick; /* Ticks when VBL counting started */
! 59: static Uint32 nVBLCount; /* Frame count */
! 60:
! 61: static bool bEmulationActive = true; /* Run emulation when started */
1.1.1.15 root 62: static bool bAccurateDelays; /* Host system has an accurate SDL_Delay()? */
1.1.1.17! root 63: static bool bIgnoreNextMouseMotion = false; /* Next mouse motion will be ignored (needed after SDL_WarpMouse) */
1.1 root 64:
65:
66: /*-----------------------------------------------------------------------*/
1.1.1.13 root 67: /**
68: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
69: */
1.1.1.15 root 70: void Main_MemorySnapShot_Capture(bool bSave)
1.1 root 71: {
1.1.1.13 root 72: int nBytes;
1.1 root 73:
1.1.1.13 root 74: /* Save/Restore details */
75: /* Only save/restore area of memory machine ie set to, eg 1Mb */
76: if (bSave)
77: {
78: nBytes = STRamEnd;
79: MemorySnapShot_Store(&nBytes, sizeof(nBytes));
80: MemorySnapShot_Store(STRam, nBytes);
81: }
82: else
83: {
84: MemorySnapShot_Store(&nBytes, sizeof(nBytes));
85: MemorySnapShot_Store(STRam, nBytes);
86: }
87: /* And Cart/TOS/Hardware area */
1.1.1.15 root 88: MemorySnapShot_Store(&RomMem[0xE00000], 0x200000);
1.1 root 89: }
90:
91:
92: /*-----------------------------------------------------------------------*/
1.1.1.13 root 93: /**
1.1.1.17! root 94: * Return current time as millisecond for performance measurements.
! 95: *
! 96: * (On Unix only time spent by Hatari itself is counted, on other
! 97: * platforms less accurate SDL "wall clock".)
! 98: */
! 99: #if HAVE_SYS_TIMES_H
! 100: #include <unistd.h>
! 101: #include <sys/times.h>
! 102: static Uint32 Main_GetTicks(void)
! 103: {
! 104: static unsigned int ticks_to_msec = 0;
! 105: struct tms fields;
! 106: if (!ticks_to_msec)
! 107: {
! 108: ticks_to_msec = sysconf(_SC_CLK_TCK);
! 109: printf("OS clock ticks / second: %d\n", ticks_to_msec);
! 110: /* Linux has 100Hz virtual clock so no accuracy loss there */
! 111: ticks_to_msec = 1000UL / ticks_to_msec;
! 112: }
! 113: /* return milliseconds (clock ticks) spent in this process
! 114: */
! 115: times(&fields);
! 116: return ticks_to_msec * fields.tms_utime;
! 117: }
! 118: #else
! 119: #define Main_GetTicks SDL_GetTicks
! 120: #endif
! 121:
! 122:
! 123: /*-----------------------------------------------------------------------*/
! 124: /**
! 125: * Pause emulation, stop sound. 'visualize' should be set true,
1.1.1.15 root 126: * unless unpause will be called immediately afterwards.
127: *
1.1.1.17! root 128: * @return true if paused now, false if was already paused
1.1.1.13 root 129: */
1.1.1.15 root 130: bool Main_PauseEmulation(bool visualize)
1.1 root 131: {
1.1.1.15 root 132: if ( !bEmulationActive )
1.1.1.17! root 133: return false;
1.1.1.15 root 134:
1.1.1.17! root 135: Audio_EnableAudio(false);
! 136: bEmulationActive = false;
1.1.1.15 root 137: if (visualize)
1.1.1.13 root 138: {
1.1.1.17! root 139: if (nFirstMilliTick)
! 140: {
! 141: int interval = Main_GetTicks() - nFirstMilliTick;
! 142: static float previous;
! 143: float current;
! 144:
! 145: current = (1000.0 * nVBLCount) / interval;
! 146: printf("SPEED: %.1f VBL/s (%d/%.1fs), diff=%.1f%%\n",
! 147: current, nVBLCount, interval/1000.0,
! 148: previous ? 100*(current-previous)/previous : 0.0);
! 149: nVBLCount = nFirstMilliTick = 0;
! 150: previous = current;
! 151: }
! 152:
1.1.1.15 root 153: Statusbar_AddMessage("Emulation paused", 100);
154: /* make sure msg gets shown */
155: Statusbar_Update(sdlscrn);
1.1.1.17! root 156:
! 157: if (bGrabMouse && !bInFullScreen)
! 158: /* Un-grab mouse pointer in windowed mode */
! 159: SDL_WM_GrabInput(SDL_GRAB_OFF);
1.1.1.13 root 160: }
1.1.1.17! root 161: return true;
1.1 root 162: }
163:
1.1.1.2 root 164: /*-----------------------------------------------------------------------*/
1.1.1.13 root 165: /**
1.1.1.15 root 166: * Start/continue emulation
167: *
1.1.1.17! root 168: * @return true if continued, false if was already running
1.1.1.13 root 169: */
1.1.1.15 root 170: bool Main_UnPauseEmulation(void)
1.1 root 171: {
1.1.1.15 root 172: if ( bEmulationActive )
1.1.1.17! root 173: return false;
1.1 root 174:
1.1.1.15 root 175: Sound_ResetBufferIndex();
176: Audio_EnableAudio(ConfigureParams.Sound.bEnableSound);
1.1.1.17! root 177: bEmulationActive = true;
1.1.1.15 root 178:
179: /* Cause full screen update (to clear all) */
180: Screen_SetFullUpdate();
1.1.1.17! root 181:
! 182: if (bGrabMouse)
! 183: /* Grab mouse pointer again */
! 184: SDL_WM_GrabInput(SDL_GRAB_ON);
! 185: return true;
1.1 root 186: }
187:
1.1.1.13 root 188: /*-----------------------------------------------------------------------*/
189: /**
190: * Optionally ask user whether to quit and set bQuitProgram accordingly
191: */
192: void Main_RequestQuit(void)
193: {
194: if (ConfigureParams.Memory.bAutoSave)
195: {
1.1.1.17! root 196: bQuitProgram = true;
! 197: MemorySnapShot_Capture(ConfigureParams.Memory.szAutoSaveFileName, false);
1.1.1.13 root 198: }
199: else if (ConfigureParams.Log.bConfirmQuit)
200: {
1.1.1.17! root 201: bQuitProgram = false; /* if set true, dialog exits */
1.1.1.13 root 202: bQuitProgram = DlgAlert_Query("All unsaved data will be lost.\nDo you really want to quit?");
203: }
204: else
205: {
1.1.1.17! root 206: bQuitProgram = true;
1.1.1.13 root 207: }
208:
209: if (bQuitProgram)
210: {
211: /* Assure that CPU core shuts down */
212: M68000_SetSpecial(SPCFLAG_BRK);
213: }
214: }
1.1.1.7 root 215:
1.1.1.12 root 216: /*-----------------------------------------------------------------------*/
1.1.1.13 root 217: /**
218: * This function waits on each emulated VBL to synchronize the real time
219: * with the emulated ST.
220: * Unfortunately SDL_Delay and other sleep functions like usleep or nanosleep
221: * are very inaccurate on some systems like Linux 2.4 or Mac OS X (they can only
222: * wait for a multiple of 10ms due to the scheduler on these systems), so we have
223: * to "busy wait" there to get an accurate timing.
224: */
1.1.1.12 root 225: void Main_WaitOnVbl(void)
226: {
1.1.1.13 root 227: int nCurrentMilliTicks;
228: static int nDestMilliTicks = 0;
229: int nFrameDuration;
230: signed int nDelay;
231:
232: nCurrentMilliTicks = SDL_GetTicks();
233:
234: nFrameDuration = 1000/nScreenRefreshRate;
235: nDelay = nDestMilliTicks - nCurrentMilliTicks;
236:
1.1.1.15 root 237: /* Do not wait if we are in fast forward mode or if we are totally out of sync */
1.1.1.17! root 238: if (ConfigureParams.System.bFastForward == true
1.1.1.13 root 239: || nDelay < -4*nFrameDuration)
240: {
1.1.1.17! root 241: if (ConfigureParams.System.bFastForward == true)
! 242: {
! 243: nVBLCount += 1;
! 244: if (!nFirstMilliTick)
! 245: nFirstMilliTick = Main_GetTicks();
! 246: else if (nRunVBLs && nVBLCount >= nRunVBLs)
! 247: {
! 248: /* show VBLs/s */
! 249: Main_PauseEmulation(true);
! 250: exit(0);
! 251: }
! 252: }
1.1.1.15 root 253: if (nFrameSkips < ConfigureParams.Screen.nFrameSkips)
254: {
255: nFrameSkips += 1;
1.1.1.17! root 256: // Log_Printf(LOG_DEBUG, "Increased frameskip to %d\n", nFrameSkips);
1.1.1.15 root 257: }
1.1.1.13 root 258: /* Only update nDestMilliTicks for next VBL */
259: nDestMilliTicks = nCurrentMilliTicks + nFrameDuration;
260: return;
261: }
1.1.1.15 root 262: /* If automatic frameskip is enabled and delay's more than twice
263: * the effect of single frameskip, decrease frameskip
264: */
265: if (nFrameSkips > 0
266: && ConfigureParams.Screen.nFrameSkips >= AUTO_FRAMESKIP_LIMIT
267: && 2*nDelay > nFrameDuration/nFrameSkips)
268: {
269: nFrameSkips -= 1;
1.1.1.17! root 270: // Log_Printf(LOG_DEBUG, "Decreased frameskip to %d\n", nFrameSkips);
1.1.1.15 root 271: }
1.1.1.12 root 272:
1.1.1.13 root 273: if (bAccurateDelays)
274: {
275: /* Accurate sleeping is possible -> use SDL_Delay to free the CPU */
276: if (nDelay > 1)
277: SDL_Delay(nDelay - 1);
278: }
279: else
280: {
281: /* No accurate SDL_Delay -> only wait if more than 5ms to go... */
282: if (nDelay > 5)
283: SDL_Delay(nDelay<10 ? nDelay-1 : 9);
284: }
285:
286: /* Now busy-wait for the right tick: */
287: while (nDelay > 0)
288: {
289: nCurrentMilliTicks = SDL_GetTicks();
290: nDelay = nDestMilliTicks - nCurrentMilliTicks;
291: }
292:
293: /* Update nDestMilliTicks for next VBL */
294: nDestMilliTicks += nFrameDuration;
1.1.1.12 root 295: }
296:
297:
298: /*-----------------------------------------------------------------------*/
1.1.1.13 root 299: /**
300: * Since SDL_Delay and friends are very inaccurate on some systems, we have
301: * to check if we can rely on this delay function.
302: */
1.1.1.12 root 303: static void Main_CheckForAccurateDelays(void)
304: {
1.1.1.13 root 305: int nStartTicks, nEndTicks;
1.1.1.12 root 306:
1.1.1.13 root 307: /* Force a task switch now, so we have a longer timeslice afterwards */
308: SDL_Delay(10);
1.1.1.12 root 309:
1.1.1.13 root 310: nStartTicks = SDL_GetTicks();
311: SDL_Delay(1);
312: nEndTicks = SDL_GetTicks();
313:
314: /* If the delay took longer than 10ms, we are on an inaccurate system! */
315: bAccurateDelays = ((nEndTicks - nStartTicks) < 9);
316:
317: if (bAccurateDelays)
318: Log_Printf(LOG_DEBUG, "Host system has accurate delays. (%d)\n", nEndTicks - nStartTicks);
319: else
1.1.1.15 root 320: Log_Printf(LOG_WARN, "Host system does not have accurate delays. (%d)\n", nEndTicks - nStartTicks);
1.1.1.12 root 321: }
322:
323:
1.1 root 324: /* ----------------------------------------------------------------------- */
1.1.1.13 root 325: /**
326: * Set mouse pointer to new coordinates and set flag to ignore the mouse event
327: * that is generated by SDL_WarpMouse().
328: */
1.1.1.9 root 329: void Main_WarpMouse(int x, int y)
330: {
1.1.1.13 root 331: SDL_WarpMouse(x, y); /* Set mouse pointer to new position */
1.1.1.17! root 332: bIgnoreNextMouseMotion = true; /* Ignore mouse motion event from SDL_WarpMouse */
1.1.1.9 root 333: }
334:
335:
336: /* ----------------------------------------------------------------------- */
1.1.1.13 root 337: /**
338: * Handle mouse motion event.
339: */
1.1.1.12 root 340: static void Main_HandleMouseMotion(SDL_Event *pEvent)
341: {
342: int dx, dy;
343: static int ax = 0, ay = 0;
344:
1.1.1.17! root 345: /* Ignore motion when position has changed right after a reset or TOS
! 346: * (especially version 4.04) might get confused and play key clicks */
! 347: if (bIgnoreNextMouseMotion || nVBLs < 10)
1.1.1.12 root 348: {
1.1.1.17! root 349: bIgnoreNextMouseMotion = false;
1.1.1.12 root 350: return;
351: }
352:
353: dx = pEvent->motion.xrel;
354: dy = pEvent->motion.yrel;
355:
1.1.1.13 root 356: /* In zoomed low res mode, we divide dx and dy by the zoom factor so that
357: * the ST mouse cursor stays in sync with the host mouse. However, we have
358: * to take care of lowest bit of dx and dy which will get lost when
359: * dividing. So we store these bits in ax and ay and add them to dx and dy
360: * the next time. */
361: if (nScreenZoomX != 1)
362: {
1.1.1.12 root 363: dx += ax;
1.1.1.13 root 364: ax = dx % nScreenZoomX;
365: dx /= nScreenZoomX;
1.1.1.12 root 366: }
1.1.1.13 root 367: if (nScreenZoomY != 1)
1.1.1.12 root 368: {
369: dy += ay;
1.1.1.13 root 370: ay = dy % nScreenZoomY;
371: dy /= nScreenZoomY;
1.1.1.12 root 372: }
373:
374: KeyboardProcessor.Mouse.dx += dx;
375: KeyboardProcessor.Mouse.dy += dy;
376: }
377:
378:
379: /* ----------------------------------------------------------------------- */
1.1.1.13 root 380: /**
381: * SDL message handler.
382: * Here we process the SDL events (keyboard, mouse, ...) and map it to
383: * Atari IKBD events.
384: */
1.1.1.8 root 385: void Main_EventHandler(void)
1.1 root 386: {
1.1.1.17! root 387: bool bContinueProcessing;
1.1.1.13 root 388: SDL_Event event;
1.1.1.17! root 389: int events;
! 390: int remotepause;
! 391:
1.1.1.15 root 392: do
1.1.1.13 root 393: {
1.1.1.17! root 394: bContinueProcessing = false;
! 395:
1.1.1.15 root 396: /* check remote process control */
1.1.1.17! root 397: remotepause = Control_CheckUpdates();
1.1.1.15 root 398:
399: if ( bEmulationActive || remotepause )
400: {
1.1.1.17! root 401: events = SDL_PollEvent(&event);
1.1.1.15 root 402: }
403: else
404: {
405: ShortCut_ActKey();
406: /* last (shortcut) event activated emulation? */
407: if ( bEmulationActive )
408: break;
1.1.1.17! root 409: events = SDL_WaitEvent(&event);
1.1.1.15 root 410: }
1.1.1.17! root 411: if (!events)
1.1.1.15 root 412: {
1.1.1.17! root 413: /* no events -> if emulation is active or
! 414: * user is quitting -> return from function.
! 415: */
1.1.1.15 root 416: continue;
417: }
1.1.1.13 root 418: switch (event.type)
419: {
1.1 root 420:
1.1.1.13 root 421: case SDL_QUIT:
422: Main_RequestQuit();
423: break;
1.1.1.17! root 424:
1.1.1.13 root 425: case SDL_MOUSEMOTION: /* Read/Update internal mouse position */
426: Main_HandleMouseMotion(&event);
1.1.1.17! root 427: bContinueProcessing = true;
1.1.1.13 root 428: break;
429:
430: case SDL_MOUSEBUTTONDOWN:
431: if (event.button.button == SDL_BUTTON_LEFT)
432: {
433: if (Keyboard.LButtonDblClk == 0)
434: Keyboard.bLButtonDown |= BUTTON_MOUSE; /* Set button down flag */
435: }
436: else if (event.button.button == SDL_BUTTON_RIGHT)
437: {
438: Keyboard.bRButtonDown |= BUTTON_MOUSE;
439: }
440: else if (event.button.button == SDL_BUTTON_MIDDLE)
441: {
442: /* Start double-click sequence in emulation time */
443: Keyboard.LButtonDblClk = 1;
444: }
445: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
446: {
447: /* Simulate pressing the "cursor down" key */
1.1.1.17! root 448: IKBD_PressSTKey(0x50, true);
1.1.1.13 root 449: }
450: else if (event.button.button == SDL_BUTTON_WHEELUP)
451: {
452: /* Simulate pressing the "cursor up" key */
1.1.1.17! root 453: IKBD_PressSTKey(0x48, true);
1.1.1.13 root 454: }
455: break;
456:
457: case SDL_MOUSEBUTTONUP:
458: if (event.button.button == SDL_BUTTON_LEFT)
459: {
460: Keyboard.bLButtonDown &= ~BUTTON_MOUSE;
461: }
462: else if (event.button.button == SDL_BUTTON_RIGHT)
463: {
464: Keyboard.bRButtonDown &= ~BUTTON_MOUSE;
465: }
466: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
467: {
468: /* Simulate releasing the "cursor down" key */
1.1.1.17! root 469: IKBD_PressSTKey(0x50, false);
1.1.1.13 root 470: }
471: else if (event.button.button == SDL_BUTTON_WHEELUP)
472: {
473: /* Simulate releasing the "cursor up" key */
1.1.1.17! root 474: IKBD_PressSTKey(0x48, false);
1.1.1.13 root 475: }
476: break;
477:
478: case SDL_KEYDOWN:
479: Keymap_KeyDown(&event.key.keysym);
480: break;
481:
482: case SDL_KEYUP:
483: Keymap_KeyUp(&event.key.keysym);
484: break;
1.1.1.17! root 485:
! 486: default:
! 487: /* don't let unknown events delay event processing */
! 488: bContinueProcessing = true;
! 489: break;
1.1.1.13 root 490: }
1.1.1.17! root 491: } while (bContinueProcessing || !(bEmulationActive || bQuitProgram));
1.1.1.13 root 492: }
493:
494:
495: /*-----------------------------------------------------------------------*/
496: /**
497: * Initialise emulation
498: */
1.1.1.8 root 499: static void Main_Init(void)
1.1 root 500: {
1.1.1.13 root 501: /* Open debug log file */
1.1.1.15 root 502: if (!Log_Init())
503: {
504: fprintf(stderr, "Logging/tracing initialization failed\n");
505: exit(-1);
506: }
1.1.1.13 root 507: Log_Printf(LOG_INFO, PROG_NAME ", compiled on: " __DATE__ ", " __TIME__ "\n");
508:
509: /* Init SDL's video subsystem. Note: Audio and joystick subsystems
510: will be initialized later (failures there are not fatal). */
511: if (SDL_Init(SDL_INIT_VIDEO) < 0)
512: {
513: fprintf(stderr, "Could not initialize the SDL library:\n %s\n", SDL_GetError() );
514: exit(-1);
515: }
516:
517: SDLGui_Init();
518: Printer_Init();
519: RS232_Init();
520: Midi_Init();
521: Screen_Init();
522: HostScreen_Init();
523: #if ENABLE_DSP_EMU
524: if (ConfigureParams.System.nDSPType == DSP_TYPE_EMU)
525: {
526: DSP_Init();
527: }
528: #endif
529: Floppy_Init();
530: Init680x0(); /* Init CPU emulation */
531: Audio_Init();
532: Keymap_Init();
533:
534: /* Init HD emulation */
535: if (ConfigureParams.HardDisk.bUseHardDiskImage)
536: {
537: char *szHardDiskImage = ConfigureParams.HardDisk.szHardDiskImage;
538: if (HDC_Init(szHardDiskImage))
539: printf("Hard drive image %s mounted.\n", szHardDiskImage);
540: else
541: printf("Couldn't open HD file: %s, or no partitions\n", szHardDiskImage);
542: }
1.1.1.16 root 543: Ide_Init();
1.1.1.13 root 544: GemDOS_Init();
545: if (ConfigureParams.HardDisk.bUseHardDiskDirectories)
546: {
547: GemDOS_InitDrives();
548: }
549:
550: if (Reset_Cold()) /* Reset all systems, load TOS image */
551: {
552: /* If loading of the TOS failed, we bring up the GUI to let the
553: * user choose another TOS ROM file. */
554: Dialog_DoProperty();
555: }
556: if (!bTosImageLoaded || bQuitProgram)
557: {
558: fprintf(stderr, "Failed to load TOS image!\n");
559: SDL_Quit();
560: exit(-2);
561: }
562:
563: IoMem_Init();
564: NvRam_Init();
565: Joy_Init();
566: Sound_Init();
1.1 root 567: }
568:
1.1.1.6 root 569:
1.1.1.2 root 570: /*-----------------------------------------------------------------------*/
1.1.1.13 root 571: /**
572: * Un-Initialise emulation
573: */
1.1.1.8 root 574: static void Main_UnInit(void)
1.1 root 575: {
1.1.1.13 root 576: Screen_ReturnFromFullScreen();
577: Floppy_UnInit();
578: HDC_UnInit();
579: Midi_UnInit();
580: RS232_UnInit();
581: Printer_UnInit();
582: IoMem_UnInit();
583: NvRam_UnInit();
584: GemDOS_UnInitDrives();
1.1.1.16 root 585: Ide_UnInit();
1.1.1.13 root 586: Joy_UnInit();
587: if (Sound_AreWeRecording())
588: Sound_EndRecording();
589: Audio_UnInit();
590: SDLGui_UnInit();
591: #if ENABLE_DSP_EMU
592: if (ConfigureParams.System.nDSPType == DSP_TYPE_EMU)
593: {
594: DSP_UnInit();
595: }
596: #endif
1.1.1.15 root 597: HostScreen_UnInit();
1.1.1.13 root 598: Screen_UnInit();
599: Exit680x0();
1.1 root 600:
1.1.1.13 root 601: /* SDL uninit: */
602: SDL_Quit();
1.1.1.10 root 603:
1.1.1.13 root 604: /* Close debug log file */
605: Log_UnInit();
1.1 root 606: }
607:
1.1.1.6 root 608:
1.1.1.2 root 609: /*-----------------------------------------------------------------------*/
1.1.1.13 root 610: /**
1.1.1.15 root 611: * Load initial configuration file(s)
612: */
613: static void Main_LoadInitialConfig(void)
614: {
615: char *psGlobalConfig;
616:
617: psGlobalConfig = malloc(FILENAME_MAX);
618: if (psGlobalConfig)
619: {
620: #if defined(__AMIGAOS4__)
621: strncpy(psGlobalConfig, CONFDIR"hatari.cfg", FILENAME_MAX);
622: #else
623: snprintf(psGlobalConfig, FILENAME_MAX, CONFDIR"%chatari.cfg", PATHSEP);
624: #endif
625: /* Try to load the global configuration file */
626: Configuration_Load(psGlobalConfig);
627:
628: free(psGlobalConfig);
629: }
630:
631: /* Now try the users configuration file */
632: Configuration_Load(NULL);
633: }
634:
635: /*-----------------------------------------------------------------------*/
636: /**
637: * Set TOS etc information and initial help message
638: */
639: static void Main_StatusbarSetup(void)
640: {
641: const char *name = NULL;
642: SDLKey key;
643:
644: key = ConfigureParams.Shortcut.withoutModifier[SHORTCUT_OPTIONS];
645: if (!key)
646: key = ConfigureParams.Shortcut.withModifier[SHORTCUT_OPTIONS];
647: if (key)
648: name = SDL_GetKeyName(key);
649: if (name)
650: {
651: char message[24], *keyname;
652: keyname = Str_ToUpper(strdup(name));
653: snprintf(message, sizeof(message), "Press %s for Options", keyname);
654: free(keyname);
655:
656: Statusbar_AddMessage(message, 6000);
657: }
658: /* update information loaded by Main_Init() */
659: Statusbar_UpdateInfo();
660: }
661:
662: /*-----------------------------------------------------------------------*/
663: /**
1.1.1.13 root 664: * Main
1.1.1.15 root 665: *
666: * Note: 'argv' cannot be declared const, MinGW would then fail to link.
1.1.1.13 root 667: */
1.1 root 668: int main(int argc, char *argv[])
669: {
1.1.1.13 root 670: /* Generate random seed */
671: srand(time(NULL));
672:
673: /* Initialize directory strings */
674: Paths_Init(argv[0]);
675:
676: /* Set default configuration values: */
677: Configuration_SetDefault();
1.1.1.8 root 678:
1.1.1.13 root 679: /* Now load the values from the configuration file */
1.1.1.15 root 680: Main_LoadInitialConfig();
1.1 root 681:
1.1.1.15 root 682: /* Check for any passed parameters */
683: if (!Opt_ParseParameters(argc, (const char**)argv))
684: {
685: return 1;
686: }
1.1.1.17! root 687: /* monitor type option might require "reset" -> true */
! 688: Configuration_Apply(true);
1.1.1.2 root 689:
1.1.1.13 root 690: #ifdef WIN32
691: Win_OpenCon();
692: #endif
1.1.1.7 root 693:
1.1.1.13 root 694: /* Needed on maemo but useful also with normal X11 window managers
695: * for window grouping when you have multiple Hatari SDL windows open
696: */
697: #if HAVE_SETENV
698: setenv("SDL_VIDEO_X11_WMCLASS", "hatari", 1);
699: #endif
1.1 root 700:
1.1.1.13 root 701: /* Init emulator system */
702: Main_Init();
1.1 root 703:
1.1.1.15 root 704: /* Set initial Statusbar information */
705: Main_StatusbarSetup();
706:
1.1.1.13 root 707: /* Check if SDL_Delay is accurate */
708: Main_CheckForAccurateDelays();
1.1.1.12 root 709:
1.1.1.13 root 710: /* Run emulation */
711: Main_UnPauseEmulation();
712: M68000_Start(); /* Start emulation */
1.1 root 713:
1.1.1.13 root 714: /* Un-init emulation system */
715: Main_UnInit();
1.1 root 716:
1.1.1.13 root 717: return 0;
1.1 root 718: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.