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