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

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

unix.superglobalmegacorp.com

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