|
|
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.1.24 root 25: #include "floppy_stx.h"
1.1 root 26: #include "gemdos.h"
1.1.1.23 root 27: #include "fdc.h"
1.1.1.4 root 28: #include "hdc.h"
1.1.1.16 root 29: #include "ide.h"
1.1.1.22 root 30: #include "acia.h"
1.1 root 31: #include "ikbd.h"
1.1.1.10 root 32: #include "ioMem.h"
1.1.1.5 root 33: #include "keymap.h"
1.1.1.10 root 34: #include "log.h"
1.1 root 35: #include "m68000.h"
36: #include "memorySnapShot.h"
1.1.1.8 root 37: #include "midi.h"
1.1.1.13 root 38: #include "nvram.h"
39: #include "paths.h"
1.1 root 40: #include "printer.h"
1.1.1.8 root 41: #include "reset.h"
1.1.1.19 root 42: #include "resolution.h"
1.1 root 43: #include "rs232.h"
44: #include "screen.h"
1.1.1.5 root 45: #include "sdlgui.h"
1.1 root 46: #include "shortcut.h"
47: #include "sound.h"
1.1.1.18 root 48: #include "dmaSnd.h"
1.1.1.15 root 49: #include "statusbar.h"
1.1.1.8 root 50: #include "stMemory.h"
1.1.1.15 root 51: #include "str.h"
1.1 root 52: #include "tos.h"
53: #include "video.h"
1.1.1.18 root 54: #include "avi_record.h"
55: #include "debugui.h"
1.1.1.19 root 56: #include "clocks_timings.h"
1.1 root 57:
1.1.1.13 root 58: #include "hatari-glue.h"
59:
60: #include "falcon/dsp.h"
1.1.1.25! root 61: #include "falcon/videl.h"
1.1 root 62:
1.1.1.19 root 63: #if HAVE_GETTIMEOFDAY
64: #include <sys/time.h>
65: #endif
66:
1.1.1.23 root 67: #ifdef WIN32
68: #include "gui-win/opencon.h"
69: #endif
1.1 root 70:
1.1.1.17 root 71: bool bQuitProgram = false; /* Flag to quit program cleanly */
1.1.1.23 root 72: static int nQuitValue; /* exit value */
1.1.1.13 root 73:
1.1.1.19 root 74: static Uint32 nRunVBLs; /* Whether and how many VBLS to run before exit */
1.1.1.17 root 75: static Uint32 nFirstMilliTick; /* Ticks when VBL counting started */
76: static Uint32 nVBLCount; /* Frame count */
1.1.1.23 root 77: static int nVBLSlowdown = 1; /* host VBL wait multiplier */
1.1.1.17 root 78:
79: static bool bEmulationActive = true; /* Run emulation when started */
1.1.1.15 root 80: static bool bAccurateDelays; /* Host system has an accurate SDL_Delay()? */
1.1.1.17 root 81: static bool bIgnoreNextMouseMotion = false; /* Next mouse motion will be ignored (needed after SDL_WarpMouse) */
1.1 root 82:
83: /*-----------------------------------------------------------------------*/
1.1.1.13 root 84: /**
1.1.1.17 root 85: * Return current time as millisecond for performance measurements.
86: *
87: * (On Unix only time spent by Hatari itself is counted, on other
88: * platforms less accurate SDL "wall clock".)
89: */
90: #if HAVE_SYS_TIMES_H
91: #include <unistd.h>
92: #include <sys/times.h>
93: static Uint32 Main_GetTicks(void)
94: {
95: static unsigned int ticks_to_msec = 0;
96: struct tms fields;
97: if (!ticks_to_msec)
98: {
99: ticks_to_msec = sysconf(_SC_CLK_TCK);
100: printf("OS clock ticks / second: %d\n", ticks_to_msec);
101: /* Linux has 100Hz virtual clock so no accuracy loss there */
102: ticks_to_msec = 1000UL / ticks_to_msec;
103: }
104: /* return milliseconds (clock ticks) spent in this process
105: */
106: times(&fields);
107: return ticks_to_msec * fields.tms_utime;
108: }
109: #else
1.1.1.18 root 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: /**
1.1.1.24 root 413: * Set mouse pointer to new x,y coordinates and set flag to ignore
414: * the mouse event that is generated by SDL_WarpMouse().
415: *
416: * Skip the request is it's not position restore and mouse warping is disabled.
1.1.1.13 root 417: */
1.1.1.24 root 418: void Main_WarpMouse(int x, int y, bool restore)
1.1.1.9 root 419: {
1.1.1.24 root 420: if (!(restore || ConfigureParams.Screen.bMouseWarp))
421: return;
422: #if WITH_SDL2
423: SDL_WarpMouseInWindow(sdlWindow, x, y);
424: #else
425: SDL_WarpMouse(x, y);
426: #endif
427: bIgnoreNextMouseMotion = true;
1.1.1.9 root 428: }
429:
430:
431: /* ----------------------------------------------------------------------- */
1.1.1.13 root 432: /**
433: * Handle mouse motion event.
434: */
1.1.1.12 root 435: static void Main_HandleMouseMotion(SDL_Event *pEvent)
436: {
437: int dx, dy;
438: static int ax = 0, ay = 0;
439:
1.1.1.17 root 440: /* Ignore motion when position has changed right after a reset or TOS
441: * (especially version 4.04) might get confused and play key clicks */
442: if (bIgnoreNextMouseMotion || nVBLs < 10)
1.1.1.12 root 443: {
1.1.1.17 root 444: bIgnoreNextMouseMotion = false;
1.1.1.12 root 445: return;
446: }
447:
448: dx = pEvent->motion.xrel;
449: dy = pEvent->motion.yrel;
450:
1.1.1.13 root 451: /* In zoomed low res mode, we divide dx and dy by the zoom factor so that
452: * the ST mouse cursor stays in sync with the host mouse. However, we have
453: * to take care of lowest bit of dx and dy which will get lost when
454: * dividing. So we store these bits in ax and ay and add them to dx and dy
455: * the next time. */
456: if (nScreenZoomX != 1)
457: {
1.1.1.12 root 458: dx += ax;
1.1.1.13 root 459: ax = dx % nScreenZoomX;
460: dx /= nScreenZoomX;
1.1.1.12 root 461: }
1.1.1.13 root 462: if (nScreenZoomY != 1)
1.1.1.12 root 463: {
464: dy += ay;
1.1.1.13 root 465: ay = dy % nScreenZoomY;
466: dy /= nScreenZoomY;
1.1.1.12 root 467: }
468:
469: KeyboardProcessor.Mouse.dx += dx;
470: KeyboardProcessor.Mouse.dy += dy;
471: }
472:
473:
474: /* ----------------------------------------------------------------------- */
1.1.1.13 root 475: /**
476: * SDL message handler.
477: * Here we process the SDL events (keyboard, mouse, ...) and map it to
478: * Atari IKBD events.
479: */
1.1.1.8 root 480: void Main_EventHandler(void)
1.1 root 481: {
1.1.1.17 root 482: bool bContinueProcessing;
1.1.1.13 root 483: SDL_Event event;
1.1.1.17 root 484: int events;
485: int remotepause;
486:
1.1.1.15 root 487: do
1.1.1.13 root 488: {
1.1.1.17 root 489: bContinueProcessing = false;
490:
1.1.1.15 root 491: /* check remote process control */
1.1.1.17 root 492: remotepause = Control_CheckUpdates();
1.1.1.15 root 493:
494: if ( bEmulationActive || remotepause )
495: {
1.1.1.17 root 496: events = SDL_PollEvent(&event);
1.1.1.15 root 497: }
498: else
499: {
500: ShortCut_ActKey();
501: /* last (shortcut) event activated emulation? */
502: if ( bEmulationActive )
503: break;
1.1.1.17 root 504: events = SDL_WaitEvent(&event);
1.1.1.15 root 505: }
1.1.1.17 root 506: if (!events)
1.1.1.15 root 507: {
1.1.1.17 root 508: /* no events -> if emulation is active or
509: * user is quitting -> return from function.
510: */
1.1.1.15 root 511: continue;
512: }
1.1.1.13 root 513: switch (event.type)
514: {
515: case SDL_QUIT:
1.1.1.23 root 516: Main_RequestQuit(0);
1.1.1.13 root 517: break;
1.1.1.25! root 518:
! 519: case SDL_KEYDOWN:
! 520: Keymap_KeyDown(&event.key.keysym);
! 521: break;
! 522:
! 523: case SDL_KEYUP:
! 524: Keymap_KeyUp(&event.key.keysym);
! 525: break;
! 526:
1.1.1.13 root 527: case SDL_MOUSEMOTION: /* Read/Update internal mouse position */
528: Main_HandleMouseMotion(&event);
1.1.1.17 root 529: bContinueProcessing = true;
1.1.1.13 root 530: break;
531:
532: case SDL_MOUSEBUTTONDOWN:
533: if (event.button.button == SDL_BUTTON_LEFT)
534: {
535: if (Keyboard.LButtonDblClk == 0)
536: Keyboard.bLButtonDown |= BUTTON_MOUSE; /* Set button down flag */
537: }
538: else if (event.button.button == SDL_BUTTON_RIGHT)
539: {
540: Keyboard.bRButtonDown |= BUTTON_MOUSE;
541: }
542: else if (event.button.button == SDL_BUTTON_MIDDLE)
543: {
544: /* Start double-click sequence in emulation time */
545: Keyboard.LButtonDblClk = 1;
546: }
1.1.1.24 root 547: #if !WITH_SDL2
1.1.1.13 root 548: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
549: {
550: /* Simulate pressing the "cursor down" key */
1.1.1.17 root 551: IKBD_PressSTKey(0x50, true);
1.1.1.13 root 552: }
553: else if (event.button.button == SDL_BUTTON_WHEELUP)
554: {
555: /* Simulate pressing the "cursor up" key */
1.1.1.17 root 556: IKBD_PressSTKey(0x48, true);
1.1.1.13 root 557: }
1.1.1.24 root 558: #endif
1.1.1.13 root 559: break;
560:
561: case SDL_MOUSEBUTTONUP:
562: if (event.button.button == SDL_BUTTON_LEFT)
563: {
564: Keyboard.bLButtonDown &= ~BUTTON_MOUSE;
565: }
566: else if (event.button.button == SDL_BUTTON_RIGHT)
567: {
568: Keyboard.bRButtonDown &= ~BUTTON_MOUSE;
569: }
1.1.1.24 root 570: #if !WITH_SDL2
1.1.1.13 root 571: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
572: {
573: /* Simulate releasing the "cursor down" key */
1.1.1.17 root 574: IKBD_PressSTKey(0x50, false);
1.1.1.13 root 575: }
576: else if (event.button.button == SDL_BUTTON_WHEELUP)
577: {
578: /* Simulate releasing the "cursor up" key */
1.1.1.17 root 579: IKBD_PressSTKey(0x48, false);
1.1.1.13 root 580: }
1.1.1.24 root 581: #endif
1.1.1.13 root 582: break;
583:
1.1.1.25! root 584: #if WITH_SDL2
! 585: case SDL_MOUSEWHEEL:
! 586: /* Simulate cursor keys on mouse wheel events */
! 587: if (event.wheel.x > 0)
! 588: {
! 589: IKBD_PressSTKey(0x4d, true);
! 590: IKBD_PressSTKey(0x4d, false);
! 591: }
! 592: else if (event.wheel.x < 0)
! 593: {
! 594: IKBD_PressSTKey(0x4b, true);
! 595: IKBD_PressSTKey(0x4b, false);
! 596: }
! 597: if (event.wheel.y < 0)
! 598: {
! 599: IKBD_PressSTKey(0x50, true);
! 600: IKBD_PressSTKey(0x50, false);
! 601: }
! 602: else if (event.wheel.y > 0)
! 603: {
! 604: IKBD_PressSTKey(0x48, true);
! 605: IKBD_PressSTKey(0x48, false);
! 606: }
1.1.1.13 root 607: break;
608:
1.1.1.25! root 609: case SDL_WINDOWEVENT:
! 610: if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED
! 611: || event.window.event == SDL_WINDOWEVENT_RESTORED)
! 612: {
! 613: SDL_UpdateRect(sdlscrn, 0, 0, 0, 0);
! 614: break;
! 615: }
! 616: bContinueProcessing = true;
1.1.1.13 root 617: break;
1.1.1.25! root 618: #endif
1.1.1.17 root 619:
1.1.1.25! root 620: default:
1.1.1.17 root 621: /* don't let unknown events delay event processing */
622: bContinueProcessing = true;
623: break;
1.1.1.13 root 624: }
1.1.1.17 root 625: } while (bContinueProcessing || !(bEmulationActive || bQuitProgram));
1.1.1.13 root 626: }
627:
628:
629: /*-----------------------------------------------------------------------*/
630: /**
1.1.1.19 root 631: * Set Hatari window title. Use NULL for default
632: */
633: void Main_SetTitle(const char *title)
634: {
1.1.1.24 root 635: #if WITH_SDL2
636: if (title)
637: SDL_SetWindowTitle(sdlWindow, title);
638: else
639: SDL_SetWindowTitle(sdlWindow, PROG_NAME);
640: #else
1.1.1.19 root 641: if (title)
642: SDL_WM_SetCaption(title, "Hatari");
643: else
644: SDL_WM_SetCaption(PROG_NAME, "Hatari");
1.1.1.24 root 645: #endif
1.1.1.19 root 646: }
647:
648: /*-----------------------------------------------------------------------*/
649: /**
1.1.1.23 root 650: * Initialise emulation for some hardware components
1.1.1.24 root 651: * It is required to init those parts before parsing the parameters
652: * (for example, we should init FDC before inserting a disk and we
653: * need to know valid joysticks before selecting default joystick IDs)
1.1.1.23 root 654: */
655: static void Main_Init_HW(void)
656: {
1.1.1.24 root 657: Joy_Init();
1.1.1.23 root 658: FDC_Init();
1.1.1.24 root 659: STX_Init();
1.1.1.25! root 660: Video_InitTimings();
1.1.1.23 root 661: }
662:
663: /*-----------------------------------------------------------------------*/
664: /**
1.1.1.13 root 665: * Initialise emulation
666: */
1.1.1.8 root 667: static void Main_Init(void)
1.1 root 668: {
1.1.1.13 root 669: /* Open debug log file */
1.1.1.15 root 670: if (!Log_Init())
671: {
672: fprintf(stderr, "Logging/tracing initialization failed\n");
673: exit(-1);
674: }
1.1.1.13 root 675: Log_Printf(LOG_INFO, PROG_NAME ", compiled on: " __DATE__ ", " __TIME__ "\n");
676:
1.1.1.24 root 677: /* Init SDL's video subsystem. Note: Audio subsystem
678: will be initialized later (failure not fatal). */
1.1.1.18 root 679: if (SDL_Init(SDL_INIT_VIDEO | Opt_GetNoParachuteFlag()) < 0)
1.1.1.13 root 680: {
681: fprintf(stderr, "Could not initialize the SDL library:\n %s\n", SDL_GetError() );
682: exit(-1);
683: }
1.1.1.23 root 684:
685: if ( IPF_Init() != true )
686: {
687: fprintf(stderr, "Could not initialize the IPF support\n" );
688: exit(-1);
689: }
690:
1.1.1.19 root 691: ClocksTimings_InitMachine ( ConfigureParams.System.nMachineType );
1.1.1.25! root 692: Video_SetTimings ( ConfigureParams.System.nMachineType , ConfigureParams.System.VideoTimingMode );
! 693:
1.1.1.19 root 694: Resolution_Init();
1.1.1.13 root 695: SDLGui_Init();
696: Printer_Init();
697: RS232_Init();
698: Midi_Init();
1.1.1.20 root 699: Control_CheckUpdates(); /* enable window embedding? */
1.1.1.25! root 700: Videl_Init();
1.1.1.13 root 701: Screen_Init();
1.1.1.19 root 702: Main_SetTitle(NULL);
1.1.1.22 root 703:
704: ACIA_Init( ACIA_Array , MachineClocks.ACIA_Freq , MachineClocks.ACIA_Freq );
705: IKBD_Init(); /* After ACIA_Init */
706:
1.1.1.18 root 707: DSP_Init();
1.1.1.13 root 708: Floppy_Init();
1.1.1.18 root 709: M68000_Init(); /* Init CPU emulation */
1.1.1.13 root 710: Audio_Init();
711: Keymap_Init();
712:
713: /* Init HD emulation */
1.1.1.18 root 714: HDC_Init();
1.1.1.16 root 715: Ide_Init();
1.1.1.13 root 716: GemDOS_Init();
717: if (ConfigureParams.HardDisk.bUseHardDiskDirectories)
718: {
1.1.1.18 root 719: /* uses variables set by HDC_Init()! */
1.1.1.13 root 720: GemDOS_InitDrives();
721: }
722:
723: if (Reset_Cold()) /* Reset all systems, load TOS image */
724: {
725: /* If loading of the TOS failed, we bring up the GUI to let the
726: * user choose another TOS ROM file. */
727: Dialog_DoProperty();
728: }
729: if (!bTosImageLoaded || bQuitProgram)
730: {
731: fprintf(stderr, "Failed to load TOS image!\n");
732: SDL_Quit();
733: exit(-2);
734: }
735:
736: IoMem_Init();
737: NvRam_Init();
738: Sound_Init();
1.1.1.18 root 739:
740: /* done as last, needs CPU & DSP running... */
741: DebugUI_Init();
1.1 root 742: }
743:
1.1.1.6 root 744:
1.1.1.2 root 745: /*-----------------------------------------------------------------------*/
1.1.1.13 root 746: /**
747: * Un-Initialise emulation
748: */
1.1.1.8 root 749: static void Main_UnInit(void)
1.1 root 750: {
1.1.1.13 root 751: Screen_ReturnFromFullScreen();
752: Floppy_UnInit();
753: HDC_UnInit();
754: Midi_UnInit();
755: RS232_UnInit();
756: Printer_UnInit();
757: IoMem_UnInit();
758: NvRam_UnInit();
759: GemDOS_UnInitDrives();
1.1.1.16 root 760: Ide_UnInit();
1.1.1.13 root 761: Joy_UnInit();
762: if (Sound_AreWeRecording())
763: Sound_EndRecording();
764: Audio_UnInit();
765: SDLGui_UnInit();
1.1.1.18 root 766: DSP_UnInit();
1.1.1.13 root 767: Screen_UnInit();
768: Exit680x0();
1.1 root 769:
1.1.1.23 root 770: IPF_Exit();
771:
1.1.1.13 root 772: /* SDL uninit: */
773: SDL_Quit();
1.1.1.10 root 774:
1.1.1.13 root 775: /* Close debug log file */
776: Log_UnInit();
1.1 root 777: }
778:
1.1.1.6 root 779:
1.1.1.2 root 780: /*-----------------------------------------------------------------------*/
1.1.1.13 root 781: /**
1.1.1.15 root 782: * Load initial configuration file(s)
783: */
784: static void Main_LoadInitialConfig(void)
785: {
786: char *psGlobalConfig;
787:
788: psGlobalConfig = malloc(FILENAME_MAX);
789: if (psGlobalConfig)
790: {
791: #if defined(__AMIGAOS4__)
792: strncpy(psGlobalConfig, CONFDIR"hatari.cfg", FILENAME_MAX);
793: #else
794: snprintf(psGlobalConfig, FILENAME_MAX, CONFDIR"%chatari.cfg", PATHSEP);
795: #endif
796: /* Try to load the global configuration file */
797: Configuration_Load(psGlobalConfig);
798:
799: free(psGlobalConfig);
800: }
801:
802: /* Now try the users configuration file */
803: Configuration_Load(NULL);
804: }
805:
806: /*-----------------------------------------------------------------------*/
807: /**
808: * Set TOS etc information and initial help message
809: */
810: static void Main_StatusbarSetup(void)
811: {
812: const char *name = NULL;
813: SDLKey key;
814:
815: key = ConfigureParams.Shortcut.withoutModifier[SHORTCUT_OPTIONS];
816: if (!key)
817: key = ConfigureParams.Shortcut.withModifier[SHORTCUT_OPTIONS];
818: if (key)
819: name = SDL_GetKeyName(key);
820: if (name)
821: {
822: char message[24], *keyname;
1.1.1.18 root 823: #ifdef _MUDFLAP
1.1.1.21 root 824: __mf_register((void*)name, 32, __MF_TYPE_GUESS, "SDL keyname");
1.1.1.18 root 825: #endif
1.1.1.15 root 826: keyname = Str_ToUpper(strdup(name));
827: snprintf(message, sizeof(message), "Press %s for Options", keyname);
828: free(keyname);
829:
1.1.1.23 root 830: Statusbar_AddMessage(message, 5000);
1.1.1.15 root 831: }
832: /* update information loaded by Main_Init() */
833: Statusbar_UpdateInfo();
834: }
835:
1.1.1.24 root 836:
1.1.1.15 root 837: /**
1.1.1.13 root 838: * Main
1.1.1.15 root 839: *
840: * Note: 'argv' cannot be declared const, MinGW would then fail to link.
1.1.1.13 root 841: */
1.1 root 842: int main(int argc, char *argv[])
843: {
1.1.1.13 root 844: /* Generate random seed */
845: srand(time(NULL));
846:
1.1.1.24 root 847: /* Logs default to stderr at start */
848: Log_Default();
849:
1.1.1.13 root 850: /* Initialize directory strings */
851: Paths_Init(argv[0]);
852:
1.1.1.23 root 853: /* Init some HW components before parsing the configuration / parameters */
854: Main_Init_HW();
855:
856: /* Set default configuration values */
1.1.1.13 root 857: Configuration_SetDefault();
1.1.1.8 root 858:
1.1.1.13 root 859: /* Now load the values from the configuration file */
1.1.1.15 root 860: Main_LoadInitialConfig();
1.1 root 861:
1.1.1.15 root 862: /* Check for any passed parameters */
1.1.1.19 root 863: if (!Opt_ParseParameters(argc, (const char * const *)argv))
1.1.1.15 root 864: {
865: return 1;
866: }
1.1.1.17 root 867: /* monitor type option might require "reset" -> true */
868: Configuration_Apply(true);
1.1.1.2 root 869:
1.1.1.13 root 870: #ifdef WIN32
871: Win_OpenCon();
872: #endif
1.1.1.7 root 873:
1.1.1.13 root 874: #if HAVE_SETENV
1.1.1.20 root 875: /* Needed on maemo but useful also with normal X11 window managers for
876: * window grouping when you have multiple Hatari SDL windows open */
1.1.1.13 root 877: setenv("SDL_VIDEO_X11_WMCLASS", "hatari", 1);
1.1.1.20 root 878:
879: /* Needed for proper behavior of Caps Lock on some systems */
880: setenv("SDL_DISABLE_LOCK_KEYS", "1", 1);
1.1.1.13 root 881: #endif
1.1 root 882:
1.1.1.13 root 883: /* Init emulator system */
884: Main_Init();
1.1 root 885:
1.1.1.15 root 886: /* Set initial Statusbar information */
887: Main_StatusbarSetup();
888:
1.1.1.13 root 889: /* Check if SDL_Delay is accurate */
890: Main_CheckForAccurateDelays();
1.1.1.12 root 891:
1.1.1.22 root 892: if ( AviRecordOnStartup ) /* Immediately starts avi recording ? */
1.1.1.19 root 893: Avi_StartRecording ( ConfigureParams.Video.AviRecordFile , ConfigureParams.Screen.bCrop ,
894: ConfigureParams.Video.AviRecordFps == 0 ?
895: ClocksTimings_GetVBLPerSec ( ConfigureParams.System.nMachineType , nScreenRefreshRate ) :
896: (Uint32)ConfigureParams.Video.AviRecordFps << CLOCKS_TIMINGS_SHIFT_VBL ,
897: 1 << CLOCKS_TIMINGS_SHIFT_VBL ,
898: ConfigureParams.Video.AviRecordVcodec );
1.1.1.18 root 899:
1.1.1.13 root 900: /* Run emulation */
901: Main_UnPauseEmulation();
902: M68000_Start(); /* Start emulation */
1.1 root 903:
1.1.1.18 root 904: if (bRecordingAvi)
905: {
906: /* cleanly close the avi file */
907: Statusbar_AddMessage("Finishing AVI file...", 100);
1.1.1.23 root 908: Statusbar_Update(sdlscrn, true);
1.1.1.18 root 909: Avi_StopRecording();
910: }
1.1.1.13 root 911: /* Un-init emulation system */
912: Main_UnInit();
1.1 root 913:
1.1.1.23 root 914: return nQuitValue;
1.1 root 915: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.