Annotation of hatari/src/main.c, revision 1.1.1.26

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
1.1.1.26! root      292:  * are very inaccurate on some systems like Linux 2.4 or macOS (they can only
        !           293:  * wait for a multiple of 10ms due to the scheduler on these systems), so we
        !           294:  * have 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.26! root      327:        /* or if we are in benchmark mode */
1.1.1.17  root      328:        if (ConfigureParams.System.bFastForward == true
1.1.1.26! root      329:            || nDelay < -4*FrameDuration_micro || nDelay > 50*FrameDuration_micro
        !           330:            || BenchmarkMode )
        !           331: 
1.1.1.13  root      332:        {
1.1.1.26! root      333:                if ( ( ConfigureParams.System.bFastForward == true )
        !           334:                  || ( BenchmarkMode == true ) )
1.1.1.17  root      335:                {
                    336:                        if (!nFirstMilliTick)
                    337:                                nFirstMilliTick = Main_GetTicks();
                    338:                }
1.1.1.15  root      339:                if (nFrameSkips < ConfigureParams.Screen.nFrameSkips)
                    340:                {
                    341:                        nFrameSkips += 1;
1.1.1.17  root      342:                        // Log_Printf(LOG_DEBUG, "Increased frameskip to %d\n", nFrameSkips);
1.1.1.15  root      343:                }
1.1.1.19  root      344:                /* Only update DestTicks for next VBL */
                    345:                DestTicks = CurrentTicks + FrameDuration_micro;
1.1.1.13  root      346:                return;
                    347:        }
1.1.1.26! root      348: 
1.1.1.15  root      349:        /* If automatic frameskip is enabled and delay's more than twice
                    350:         * the effect of single frameskip, decrease frameskip
                    351:         */
                    352:        if (nFrameSkips > 0
                    353:            && ConfigureParams.Screen.nFrameSkips >= AUTO_FRAMESKIP_LIMIT
1.1.1.19  root      354:            && 2*nDelay > FrameDuration_micro/nFrameSkips)
1.1.1.15  root      355:        {
                    356:                nFrameSkips -= 1;
1.1.1.17  root      357:                // Log_Printf(LOG_DEBUG, "Decreased frameskip to %d\n", nFrameSkips);
1.1.1.15  root      358:        }
1.1.1.12  root      359: 
1.1.1.13  root      360:        if (bAccurateDelays)
                    361:        {
                    362:                /* Accurate sleeping is possible -> use SDL_Delay to free the CPU */
1.1.1.19  root      363:                if (nDelay > 1000)
                    364:                        Time_Delay(nDelay - 1000);
1.1.1.13  root      365:        }
                    366:        else
                    367:        {
                    368:                /* No accurate SDL_Delay -> only wait if more than 5ms to go... */
1.1.1.19  root      369:                if (nDelay > 5000)
                    370:                        Time_Delay(nDelay<10000 ? nDelay-1000 : 9000);
1.1.1.13  root      371:        }
                    372: 
                    373:        /* Now busy-wait for the right tick: */
                    374:        while (nDelay > 0)
                    375:        {
1.1.1.19  root      376:                CurrentTicks = Time_GetTicks();
                    377:                nDelay = DestTicks - CurrentTicks;
1.1.1.23  root      378:                /* If the delay is still bigger than one frame, somebody
                    379:                 * played tricks with the system clock and we have to abort */
                    380:                if (nDelay > FrameDuration_micro)
                    381:                        break;
1.1.1.13  root      382:        }
                    383: 
1.1.1.19  root      384: //printf ( "tick %lld\n" , CurrentTicks );
                    385:        /* Update DestTicks for next VBL */
                    386:        DestTicks += FrameDuration_micro;
1.1.1.12  root      387: }
                    388: 
                    389: 
                    390: /*-----------------------------------------------------------------------*/
1.1.1.13  root      391: /**
                    392:  * Since SDL_Delay and friends are very inaccurate on some systems, we have
                    393:  * to check if we can rely on this delay function.
                    394:  */
1.1.1.12  root      395: static void Main_CheckForAccurateDelays(void)
                    396: {
1.1.1.13  root      397:        int nStartTicks, nEndTicks;
1.1.1.12  root      398: 
1.1.1.13  root      399:        /* Force a task switch now, so we have a longer timeslice afterwards */
                    400:        SDL_Delay(10);
1.1.1.12  root      401: 
1.1.1.13  root      402:        nStartTicks = SDL_GetTicks();
                    403:        SDL_Delay(1);
                    404:        nEndTicks = SDL_GetTicks();
                    405: 
                    406:        /* If the delay took longer than 10ms, we are on an inaccurate system! */
                    407:        bAccurateDelays = ((nEndTicks - nStartTicks) < 9);
                    408: 
                    409:        if (bAccurateDelays)
                    410:                Log_Printf(LOG_DEBUG, "Host system has accurate delays. (%d)\n", nEndTicks - nStartTicks);
                    411:        else
1.1.1.15  root      412:                Log_Printf(LOG_WARN, "Host system does not have accurate delays. (%d)\n", nEndTicks - nStartTicks);
1.1.1.12  root      413: }
                    414: 
                    415: 
1.1       root      416: /* ----------------------------------------------------------------------- */
1.1.1.13  root      417: /**
1.1.1.24  root      418:  * Set mouse pointer to new x,y coordinates and set flag to ignore
                    419:  * the mouse event that is generated by SDL_WarpMouse().
                    420:  *
                    421:  * Skip the request is it's not position restore and mouse warping is disabled.
1.1.1.13  root      422:  */
1.1.1.24  root      423: void Main_WarpMouse(int x, int y, bool restore)
1.1.1.9   root      424: {
1.1.1.24  root      425:        if (!(restore || ConfigureParams.Screen.bMouseWarp))
                    426:                return;
                    427: #if WITH_SDL2
                    428:        SDL_WarpMouseInWindow(sdlWindow, x, y);
                    429: #else
                    430:        SDL_WarpMouse(x, y);
                    431: #endif
                    432:        bIgnoreNextMouseMotion = true;
1.1.1.9   root      433: }
                    434: 
                    435: 
                    436: /* ----------------------------------------------------------------------- */
1.1.1.13  root      437: /**
                    438:  * Handle mouse motion event.
                    439:  */
1.1.1.12  root      440: static void Main_HandleMouseMotion(SDL_Event *pEvent)
                    441: {
                    442:        int dx, dy;
                    443:        static int ax = 0, ay = 0;
                    444: 
1.1.1.17  root      445:        /* Ignore motion when position has changed right after a reset or TOS
                    446:         * (especially version 4.04) might get confused and play key clicks */
                    447:        if (bIgnoreNextMouseMotion || nVBLs < 10)
1.1.1.12  root      448:        {
1.1.1.17  root      449:                bIgnoreNextMouseMotion = false;
1.1.1.12  root      450:                return;
                    451:        }
                    452: 
                    453:        dx = pEvent->motion.xrel;
                    454:        dy = pEvent->motion.yrel;
                    455: 
1.1.1.13  root      456:        /* In zoomed low res mode, we divide dx and dy by the zoom factor so that
                    457:         * the ST mouse cursor stays in sync with the host mouse. However, we have
                    458:         * to take care of lowest bit of dx and dy which will get lost when
                    459:         * dividing. So we store these bits in ax and ay and add them to dx and dy
                    460:         * the next time. */
                    461:        if (nScreenZoomX != 1)
                    462:        {
1.1.1.12  root      463:                dx += ax;
1.1.1.13  root      464:                ax = dx % nScreenZoomX;
                    465:                dx /= nScreenZoomX;
1.1.1.12  root      466:        }
1.1.1.13  root      467:        if (nScreenZoomY != 1)
1.1.1.12  root      468:        {
                    469:                dy += ay;
1.1.1.13  root      470:                ay = dy % nScreenZoomY;
                    471:                dy /= nScreenZoomY;
1.1.1.12  root      472:        }
                    473: 
                    474:        KeyboardProcessor.Mouse.dx += dx;
                    475:        KeyboardProcessor.Mouse.dy += dy;
                    476: }
                    477: 
                    478: 
                    479: /* ----------------------------------------------------------------------- */
1.1.1.13  root      480: /**
                    481:  * SDL message handler.
                    482:  * Here we process the SDL events (keyboard, mouse, ...) and map it to
                    483:  * Atari IKBD events.
                    484:  */
1.1.1.8   root      485: void Main_EventHandler(void)
1.1       root      486: {
1.1.1.17  root      487:        bool bContinueProcessing;
1.1.1.13  root      488:        SDL_Event event;
1.1.1.17  root      489:        int events;
                    490:        int remotepause;
                    491: 
1.1.1.15  root      492:        do
1.1.1.13  root      493:        {
1.1.1.17  root      494:                bContinueProcessing = false;
                    495: 
1.1.1.15  root      496:                /* check remote process control */
1.1.1.17  root      497:                remotepause = Control_CheckUpdates();
1.1.1.15  root      498: 
                    499:                if ( bEmulationActive || remotepause )
                    500:                {
1.1.1.17  root      501:                        events = SDL_PollEvent(&event);
1.1.1.15  root      502:                }
                    503:                else
                    504:                {
                    505:                        ShortCut_ActKey();
                    506:                        /* last (shortcut) event activated emulation? */
                    507:                        if ( bEmulationActive )
                    508:                                break;
1.1.1.17  root      509:                        events = SDL_WaitEvent(&event);
1.1.1.15  root      510:                }
1.1.1.17  root      511:                if (!events)
1.1.1.15  root      512:                {
1.1.1.17  root      513:                        /* no events -> if emulation is active or
                    514:                         * user is quitting -> return from function.
                    515:                         */
1.1.1.15  root      516:                        continue;
                    517:                }
1.1.1.13  root      518:                switch (event.type)
                    519:                {
                    520:                 case SDL_QUIT:
1.1.1.23  root      521:                        Main_RequestQuit(0);
1.1.1.13  root      522:                        break;
1.1.1.25  root      523: 
                    524:                 case SDL_KEYDOWN:
1.1.1.26! root      525: #if WITH_SDL2
        !           526:                        if (event.key.repeat) {
        !           527:                                bContinueProcessing = true;
        !           528:                                break;
        !           529:                        }
        !           530: #endif
1.1.1.25  root      531:                        Keymap_KeyDown(&event.key.keysym);
                    532:                        break;
                    533: 
                    534:                 case SDL_KEYUP:
                    535:                        Keymap_KeyUp(&event.key.keysym);
                    536:                        break;
                    537: 
1.1.1.13  root      538:                 case SDL_MOUSEMOTION:               /* Read/Update internal mouse position */
                    539:                        Main_HandleMouseMotion(&event);
1.1.1.17  root      540:                        bContinueProcessing = true;
1.1.1.13  root      541:                        break;
                    542: 
                    543:                 case SDL_MOUSEBUTTONDOWN:
                    544:                        if (event.button.button == SDL_BUTTON_LEFT)
                    545:                        {
                    546:                                if (Keyboard.LButtonDblClk == 0)
                    547:                                        Keyboard.bLButtonDown |= BUTTON_MOUSE;  /* Set button down flag */
                    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_MIDDLE)
                    554:                        {
                    555:                                /* Start double-click sequence in emulation time */
                    556:                                Keyboard.LButtonDblClk = 1;
                    557:                        }
1.1.1.24  root      558: #if !WITH_SDL2
1.1.1.13  root      559:                        else if (event.button.button == SDL_BUTTON_WHEELDOWN)
                    560:                        {
                    561:                                /* Simulate pressing the "cursor down" key */
1.1.1.17  root      562:                                IKBD_PressSTKey(0x50, true);
1.1.1.13  root      563:                        }
                    564:                        else if (event.button.button == SDL_BUTTON_WHEELUP)
                    565:                        {
                    566:                                /* Simulate pressing the "cursor up" key */
1.1.1.17  root      567:                                IKBD_PressSTKey(0x48, true);
1.1.1.13  root      568:                        }
1.1.1.24  root      569: #endif
1.1.1.13  root      570:                        break;
                    571: 
                    572:                 case SDL_MOUSEBUTTONUP:
                    573:                        if (event.button.button == SDL_BUTTON_LEFT)
                    574:                        {
                    575:                                Keyboard.bLButtonDown &= ~BUTTON_MOUSE;
                    576:                        }
                    577:                        else if (event.button.button == SDL_BUTTON_RIGHT)
                    578:                        {
                    579:                                Keyboard.bRButtonDown &= ~BUTTON_MOUSE;
                    580:                        }
1.1.1.24  root      581: #if !WITH_SDL2
1.1.1.13  root      582:                        else if (event.button.button == SDL_BUTTON_WHEELDOWN)
                    583:                        {
                    584:                                /* Simulate releasing the "cursor down" key */
1.1.1.17  root      585:                                IKBD_PressSTKey(0x50, false);
1.1.1.13  root      586:                        }
                    587:                        else if (event.button.button == SDL_BUTTON_WHEELUP)
                    588:                        {
                    589:                                /* Simulate releasing the "cursor up" key */
1.1.1.17  root      590:                                IKBD_PressSTKey(0x48, false);
1.1.1.13  root      591:                        }
1.1.1.24  root      592: #endif
1.1.1.13  root      593:                        break;
                    594: 
1.1.1.25  root      595: #if WITH_SDL2
                    596:                 case SDL_MOUSEWHEEL:
                    597:                        /* Simulate cursor keys on mouse wheel events */
                    598:                        if (event.wheel.x > 0)
                    599:                        {
                    600:                                IKBD_PressSTKey(0x4d, true);
                    601:                                IKBD_PressSTKey(0x4d, false);
                    602:                        }
                    603:                        else if (event.wheel.x < 0)
                    604:                        {
                    605:                                IKBD_PressSTKey(0x4b, true);
                    606:                                IKBD_PressSTKey(0x4b, false);
                    607:                        }
                    608:                        if (event.wheel.y < 0)
                    609:                        {
                    610:                                IKBD_PressSTKey(0x50, true);
                    611:                                IKBD_PressSTKey(0x50, false);
                    612:                        }
                    613:                        else if (event.wheel.y > 0)
                    614:                        {
                    615:                                IKBD_PressSTKey(0x48, true);
                    616:                                IKBD_PressSTKey(0x48, false);
                    617:                        }
1.1.1.13  root      618:                        break;
                    619: 
1.1.1.25  root      620:                 case SDL_WINDOWEVENT:
1.1.1.26! root      621:                        /* Note: any changes here should most likely be done
        !           622:                         * also in sdlgui.c::SDLGui_DoDialog()
        !           623:                         */
1.1.1.25  root      624:                        if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED
1.1.1.26! root      625:                            || event.window.event == SDL_WINDOWEVENT_RESTORED
        !           626:                            || event.window.event == SDL_WINDOWEVENT_EXPOSED)
1.1.1.25  root      627:                        {
                    628:                                SDL_UpdateRect(sdlscrn, 0, 0, 0, 0);
1.1.1.26! root      629:                        }
        !           630:                        if (event.window.event == SDL_WINDOWEVENT_EXPOSED
        !           631:                            && !ConfigureParams.Screen.bUseSdlRenderer)
        !           632:                        {
        !           633:                                /* Hack: Redraw screen here when going into
        !           634:                                 * fullscreen mode without SDL renderer */
        !           635:                                sdlscrn = SDL_GetWindowSurface(sdlWindow);
        !           636:                                Screen_SetFullUpdate();
        !           637:                                Statusbar_Init(sdlscrn);
1.1.1.25  root      638:                        }
                    639:                        bContinueProcessing = true;
1.1.1.13  root      640:                        break;
1.1.1.25  root      641: #endif
1.1.1.17  root      642: 
1.1.1.25  root      643:                 default:
1.1.1.17  root      644:                        /* don't let unknown events delay event processing */
                    645:                        bContinueProcessing = true;
                    646:                        break;
1.1.1.13  root      647:                }
1.1.1.17  root      648:        } while (bContinueProcessing || !(bEmulationActive || bQuitProgram));
1.1.1.13  root      649: }
                    650: 
                    651: 
                    652: /*-----------------------------------------------------------------------*/
                    653: /**
1.1.1.19  root      654:  * Set Hatari window title. Use NULL for default
                    655:  */
                    656: void Main_SetTitle(const char *title)
                    657: {
1.1.1.24  root      658: #if WITH_SDL2
                    659:        if (title)
                    660:                SDL_SetWindowTitle(sdlWindow, title);
                    661:        else
                    662:                SDL_SetWindowTitle(sdlWindow, PROG_NAME);
                    663: #else
1.1.1.19  root      664:        if (title)
                    665:                SDL_WM_SetCaption(title, "Hatari");
                    666:        else
                    667:                SDL_WM_SetCaption(PROG_NAME, "Hatari");
1.1.1.24  root      668: #endif
1.1.1.19  root      669: }
                    670: 
                    671: /*-----------------------------------------------------------------------*/
                    672: /**
1.1.1.23  root      673:  * Initialise emulation for some hardware components
1.1.1.24  root      674:  * It is required to init those parts before parsing the parameters
                    675:  * (for example, we should init FDC before inserting a disk and we
                    676:  * need to know valid joysticks before selecting default joystick IDs)
1.1.1.23  root      677:  */
                    678: static void Main_Init_HW(void)
                    679: {
1.1.1.24  root      680:        Joy_Init();
1.1.1.23  root      681:        FDC_Init();
1.1.1.24  root      682:        STX_Init();
1.1.1.25  root      683:        Video_InitTimings();
1.1.1.23  root      684: }
                    685: 
                    686: /*-----------------------------------------------------------------------*/
                    687: /**
1.1.1.13  root      688:  * Initialise emulation
                    689:  */
1.1.1.8   root      690: static void Main_Init(void)
1.1       root      691: {
1.1.1.13  root      692:        /* Open debug log file */
1.1.1.15  root      693:        if (!Log_Init())
                    694:        {
                    695:                fprintf(stderr, "Logging/tracing initialization failed\n");
                    696:                exit(-1);
                    697:        }
1.1.1.13  root      698:        Log_Printf(LOG_INFO, PROG_NAME ", compiled on:  " __DATE__ ", " __TIME__ "\n");
                    699: 
1.1.1.24  root      700:        /* Init SDL's video subsystem. Note: Audio subsystem
                    701:           will be initialized later (failure not fatal). */
1.1.1.18  root      702:        if (SDL_Init(SDL_INIT_VIDEO | Opt_GetNoParachuteFlag()) < 0)
1.1.1.13  root      703:        {
                    704:                fprintf(stderr, "Could not initialize the SDL library:\n %s\n", SDL_GetError() );
                    705:                exit(-1);
                    706:        }
1.1.1.23  root      707: 
                    708:        if ( IPF_Init() != true )
                    709:        {
                    710:                fprintf(stderr, "Could not initialize the IPF support\n" );
                    711:                exit(-1);
                    712:        }
                    713: 
1.1.1.19  root      714:        ClocksTimings_InitMachine ( ConfigureParams.System.nMachineType );
1.1.1.25  root      715:        Video_SetTimings ( ConfigureParams.System.nMachineType , ConfigureParams.System.VideoTimingMode );
                    716: 
1.1.1.19  root      717:        Resolution_Init();
1.1.1.13  root      718:        SDLGui_Init();
                    719:        Printer_Init();
                    720:        RS232_Init();
                    721:        Midi_Init();
1.1.1.20  root      722:        Control_CheckUpdates();       /* enable window embedding? */
1.1.1.25  root      723:        Videl_Init();
1.1.1.13  root      724:        Screen_Init();
1.1.1.19  root      725:        Main_SetTitle(NULL);
1.1.1.22  root      726: 
1.1.1.26! root      727:        STMemory_Init ( ConfigureParams.Memory.STRamSize_KB * 1024 );
        !           728: 
1.1.1.22  root      729:        ACIA_Init( ACIA_Array , MachineClocks.ACIA_Freq , MachineClocks.ACIA_Freq );
                    730:        IKBD_Init();                    /* After ACIA_Init */
                    731: 
1.1.1.18  root      732:        DSP_Init();
1.1.1.13  root      733:        Floppy_Init();
1.1.1.18  root      734:        M68000_Init();                /* Init CPU emulation */
1.1.1.13  root      735:        Audio_Init();
                    736:        Keymap_Init();
                    737: 
                    738:        /* Init HD emulation */
1.1.1.18  root      739:        HDC_Init();
1.1.1.16  root      740:        Ide_Init();
1.1.1.13  root      741:        GemDOS_Init();
                    742:        if (ConfigureParams.HardDisk.bUseHardDiskDirectories)
                    743:        {
1.1.1.18  root      744:                /* uses variables set by HDC_Init()! */
1.1.1.13  root      745:                GemDOS_InitDrives();
                    746:        }
                    747: 
                    748:        if (Reset_Cold())             /* Reset all systems, load TOS image */
                    749:        {
                    750:                /* If loading of the TOS failed, we bring up the GUI to let the
                    751:                 * user choose another TOS ROM file. */
                    752:                Dialog_DoProperty();
                    753:        }
                    754:        if (!bTosImageLoaded || bQuitProgram)
                    755:        {
1.1.1.26! root      756:                if (!bTosImageLoaded)
        !           757:                        fprintf(stderr, "Failed to load TOS image!\n");
1.1.1.13  root      758:                SDL_Quit();
                    759:                exit(-2);
                    760:        }
                    761: 
                    762:        IoMem_Init();
                    763:        NvRam_Init();
                    764:        Sound_Init();
1.1.1.18  root      765:        
                    766:        /* done as last, needs CPU & DSP running... */
                    767:        DebugUI_Init();
1.1       root      768: }
                    769: 
1.1.1.6   root      770: 
1.1.1.2   root      771: /*-----------------------------------------------------------------------*/
1.1.1.13  root      772: /**
                    773:  * Un-Initialise emulation
                    774:  */
1.1.1.8   root      775: static void Main_UnInit(void)
1.1       root      776: {
1.1.1.13  root      777:        Screen_ReturnFromFullScreen();
                    778:        Floppy_UnInit();
                    779:        HDC_UnInit();
                    780:        Midi_UnInit();
                    781:        RS232_UnInit();
                    782:        Printer_UnInit();
                    783:        IoMem_UnInit();
                    784:        NvRam_UnInit();
                    785:        GemDOS_UnInitDrives();
1.1.1.16  root      786:        Ide_UnInit();
1.1.1.13  root      787:        Joy_UnInit();
                    788:        if (Sound_AreWeRecording())
                    789:                Sound_EndRecording();
                    790:        Audio_UnInit();
                    791:        SDLGui_UnInit();
1.1.1.18  root      792:        DSP_UnInit();
1.1.1.13  root      793:        Screen_UnInit();
                    794:        Exit680x0();
1.1       root      795: 
1.1.1.23  root      796:        IPF_Exit();
                    797: 
1.1.1.13  root      798:        /* SDL uninit: */
                    799:        SDL_Quit();
1.1.1.10  root      800: 
1.1.1.13  root      801:        /* Close debug log file */
                    802:        Log_UnInit();
1.1       root      803: }
                    804: 
1.1.1.6   root      805: 
1.1.1.2   root      806: /*-----------------------------------------------------------------------*/
1.1.1.13  root      807: /**
1.1.1.15  root      808:  * Load initial configuration file(s)
                    809:  */
                    810: static void Main_LoadInitialConfig(void)
                    811: {
                    812:        char *psGlobalConfig;
                    813: 
                    814:        psGlobalConfig = malloc(FILENAME_MAX);
                    815:        if (psGlobalConfig)
                    816:        {
                    817: #if defined(__AMIGAOS4__)
                    818:                strncpy(psGlobalConfig, CONFDIR"hatari.cfg", FILENAME_MAX);
                    819: #else
                    820:                snprintf(psGlobalConfig, FILENAME_MAX, CONFDIR"%chatari.cfg", PATHSEP);
                    821: #endif
                    822:                /* Try to load the global configuration file */
                    823:                Configuration_Load(psGlobalConfig);
                    824: 
                    825:                free(psGlobalConfig);
                    826:        }
                    827: 
                    828:        /* Now try the users configuration file */
                    829:        Configuration_Load(NULL);
                    830: }
                    831: 
                    832: /*-----------------------------------------------------------------------*/
                    833: /**
                    834:  * Set TOS etc information and initial help message
                    835:  */
                    836: static void Main_StatusbarSetup(void)
                    837: {
                    838:        const char *name = NULL;
                    839:        SDLKey key;
                    840: 
                    841:        key = ConfigureParams.Shortcut.withoutModifier[SHORTCUT_OPTIONS];
                    842:        if (!key)
                    843:                key = ConfigureParams.Shortcut.withModifier[SHORTCUT_OPTIONS];
                    844:        if (key)
                    845:                name = SDL_GetKeyName(key);
                    846:        if (name)
                    847:        {
                    848:                char message[24], *keyname;
1.1.1.18  root      849: #ifdef _MUDFLAP
1.1.1.21  root      850:                __mf_register((void*)name, 32, __MF_TYPE_GUESS, "SDL keyname");
1.1.1.18  root      851: #endif
1.1.1.15  root      852:                keyname = Str_ToUpper(strdup(name));
                    853:                snprintf(message, sizeof(message), "Press %s for Options", keyname);
                    854:                free(keyname);
                    855: 
1.1.1.23  root      856:                Statusbar_AddMessage(message, 5000);
1.1.1.15  root      857:        }
                    858:        /* update information loaded by Main_Init() */
                    859:        Statusbar_UpdateInfo();
                    860: }
                    861: 
1.1.1.24  root      862: 
1.1.1.15  root      863: /**
1.1.1.13  root      864:  * Main
1.1.1.15  root      865:  * 
                    866:  * Note: 'argv' cannot be declared const, MinGW would then fail to link.
1.1.1.13  root      867:  */
1.1       root      868: int main(int argc, char *argv[])
                    869: {
1.1.1.13  root      870:        /* Generate random seed */
                    871:        srand(time(NULL));
                    872: 
1.1.1.24  root      873:        /* Logs default to stderr at start */
                    874:        Log_Default();
                    875: 
1.1.1.13  root      876:        /* Initialize directory strings */
                    877:        Paths_Init(argv[0]);
                    878: 
1.1.1.23  root      879:        /* Init some HW components before parsing the configuration / parameters */
                    880:        Main_Init_HW();
                    881: 
                    882:        /* Set default configuration values */
1.1.1.13  root      883:        Configuration_SetDefault();
1.1.1.8   root      884: 
1.1.1.13  root      885:        /* Now load the values from the configuration file */
1.1.1.15  root      886:        Main_LoadInitialConfig();
1.1       root      887: 
1.1.1.15  root      888:        /* Check for any passed parameters */
1.1.1.19  root      889:        if (!Opt_ParseParameters(argc, (const char * const *)argv))
1.1.1.15  root      890:        {
                    891:                return 1;
                    892:        }
1.1.1.17  root      893:        /* monitor type option might require "reset" -> true */
                    894:        Configuration_Apply(true);
1.1.1.2   root      895: 
1.1.1.13  root      896: #ifdef WIN32
                    897:        Win_OpenCon();
                    898: #endif
1.1.1.7   root      899: 
1.1.1.13  root      900: #if HAVE_SETENV
1.1.1.20  root      901:        /* Needed on maemo but useful also with normal X11 window managers for
                    902:         * window grouping when you have multiple Hatari SDL windows open */
1.1.1.13  root      903:        setenv("SDL_VIDEO_X11_WMCLASS", "hatari", 1);
1.1.1.20  root      904: 
                    905:        /* Needed for proper behavior of Caps Lock on some systems */
                    906:        setenv("SDL_DISABLE_LOCK_KEYS", "1", 1);
1.1.1.13  root      907: #endif
1.1       root      908: 
1.1.1.13  root      909:        /* Init emulator system */
                    910:        Main_Init();
1.1       root      911: 
1.1.1.15  root      912:        /* Set initial Statusbar information */
                    913:        Main_StatusbarSetup();
                    914:        
1.1.1.13  root      915:        /* Check if SDL_Delay is accurate */
                    916:        Main_CheckForAccurateDelays();
1.1.1.12  root      917: 
1.1.1.22  root      918:        if ( AviRecordOnStartup )       /* Immediately starts avi recording ? */
1.1.1.19  root      919:                Avi_StartRecording ( ConfigureParams.Video.AviRecordFile , ConfigureParams.Screen.bCrop ,
                    920:                        ConfigureParams.Video.AviRecordFps == 0 ?
                    921:                                ClocksTimings_GetVBLPerSec ( ConfigureParams.System.nMachineType , nScreenRefreshRate ) :
                    922:                                (Uint32)ConfigureParams.Video.AviRecordFps << CLOCKS_TIMINGS_SHIFT_VBL ,
                    923:                        1 << CLOCKS_TIMINGS_SHIFT_VBL ,
                    924:                        ConfigureParams.Video.AviRecordVcodec );
1.1.1.18  root      925: 
1.1.1.13  root      926:        /* Run emulation */
                    927:        Main_UnPauseEmulation();
                    928:        M68000_Start();                 /* Start emulation */
1.1       root      929: 
1.1.1.18  root      930:        if (bRecordingAvi)
                    931:        {
                    932:                /* cleanly close the avi file */
                    933:                Statusbar_AddMessage("Finishing AVI file...", 100);
1.1.1.23  root      934:                Statusbar_Update(sdlscrn, true);
1.1.1.18  root      935:                Avi_StopRecording();
                    936:        }
1.1.1.13  root      937:        /* Un-init emulation system */
                    938:        Main_UnInit();
1.1       root      939: 
1.1.1.23  root      940:        return nQuitValue;
1.1       root      941: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.