Annotation of previous/src/main.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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