Annotation of previous_trunk/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 <errno.h>
                     13: #include <signal.h>
                     14: 
                     15: #include "main.h"
                     16: #include "configuration.h"
                     17: #include "dialog.h"
                     18: #include "ioMem.h"
                     19: #include "keymap.h"
                     20: #include "log.h"
                     21: #include "m68000.h"
                     22: #include "paths.h"
                     23: #include "reset.h"
                     24: #include "screen.h"
                     25: #include "sdlgui.h"
                     26: #include "shortcut.h"
                     27: #include "snd.h"
                     28: #include "statusbar.h"
                     29: #include "nextMemory.h"
                     30: #include "str.h"
                     31: #include "video.h"
                     32: #include "audio.h"
                     33: #include "debugui.h"
                     34: #include "file.h"
                     35: #include "dsp.h"
                     36: #include "host.h"
                     37: #include "dimension.hpp"
                     38: 
                     39: #include "hatari-glue.h"
                     40: #include "NextBus.hpp"
                     41: 
                     42: #if HAVE_GETTIMEOFDAY
                     43: #include <sys/time.h>
                     44: #endif
                     45: 
                     46: int nFrameSkips;
                     47: 
                     48: bool bQuitProgram = false;                /* Flag to quit program cleanly */
                     49: 
                     50: static bool bEmulationActive = true;      /* Run emulation when started */
                     51: static bool bAccurateDelays;              /* Host system has an accurate SDL_Delay()? */
                     52: static bool bIgnoreNextMouseMotion = false;  /* Next mouse motion will be ignored (needed after SDL_WarpMouse) */
                     53: 
                     54: volatile int mainPauseEmulation;
                     55: 
                     56: typedef const char* (*report_func)(double realTime, double hostTime);
                     57: 
                     58: typedef struct {
                     59:     const char*       label;
                     60:     const report_func report;
                     61: } report_t;
                     62: 
                     63: static double lastRT;
                     64: static Uint64 lastCycles;
                     65: static double speedFactor;
                     66: static char   speedMsg[32];
                     67: 
                     68: static void Main_Speed(double realTime, double hostTime) {
                     69:     double dRT = realTime - lastRT;
                     70:     speedFactor = nCyclesMainCounter - lastCycles;
                     71:     speedFactor /= ConfigureParams.System.nCpuFreq;
                     72:     speedFactor /= 1000 * 1000;
                     73:     speedFactor /= dRT;
                     74:     lastRT     = realTime;
                     75:     lastCycles = nCyclesMainCounter;
                     76: }
                     77: 
                     78: void Main_SpeedReset(void) {
                     79:     double realTime, hostTime;
                     80:     host_time(&realTime, &hostTime);
                     81:     lastRT     = realTime;
                     82:     lastCycles = nCyclesMainCounter;
                     83:     
                     84:     Log_Printf(LOG_WARN, "Realtime mode %s.\n", ConfigureParams.System.bRealtime ? "enabled" : "disabled");
                     85: }
                     86: 
                     87: const char* Main_SpeedMsg() {
                     88:     speedMsg[0] = 0;
                     89:     if(speedFactor > 0) {
                     90:         if(ConfigureParams.System.bRealtime) {
                     91:             sprintf(speedMsg, "%dMHz/", (int)(ConfigureParams.System.nCpuFreq * speedFactor + 0.5));
                     92:         } else {
                     93:             if ((speedFactor < 0.9) || (speedFactor > 1.1))
                     94:                 sprintf(speedMsg, "%.1fx%dMHz/", speedFactor, ConfigureParams.System.nCpuFreq);
                     95:             else
                     96:                 sprintf(speedMsg, "%dMHz/",                   ConfigureParams.System.nCpuFreq);
                     97:         }
                     98:     }
                     99:     return speedMsg;
                    100: }
                    101: 
                    102: #if ENABLE_TESTING
                    103: static const report_t reports[] = {
                    104:     {"ND",    nd_reports},
                    105:     {"Host",  host_report},
                    106: };
                    107: #endif
                    108: 
                    109: /*-----------------------------------------------------------------------*/
                    110: /**
                    111:  * Pause emulation, stop sound.  'visualize' should be set true,
                    112:  * unless unpause will be called immediately afterwards.
                    113:  * 
                    114:  * @return true if paused now, false if was already paused
                    115:  */
                    116: bool Main_PauseEmulation(bool visualize) {
                    117:        if ( !bEmulationActive )
                    118:                return false;
                    119: 
                    120:        bEmulationActive = false;
                    121:     host_pause_time(!(bEmulationActive));
                    122:     Screen_Pause(true);
                    123:     Sound_Pause(true);
                    124:     NextBus_Pause(true);
                    125:     
                    126:        if (visualize) {
                    127:                Statusbar_AddMessage("Emulation paused", 100);
                    128:                /* make sure msg gets shown */
                    129:                Statusbar_Update(sdlscrn);
                    130: 
                    131:                if (bGrabMouse && !bInFullScreen) {
                    132:                        /* Un-grab mouse pointer in windowed mode */
                    133:                        SDL_SetRelativeMouseMode(SDL_FALSE);
                    134:             SDL_SetWindowGrab(sdlWindow, SDL_FALSE);
                    135:         }
                    136:        }
                    137:        return true;
                    138: }
                    139: 
                    140: /*-----------------------------------------------------------------------*/
                    141: /**
                    142:  * Start/continue emulation
                    143:  * 
                    144:  * @return true if continued, false if was already running
                    145:  */
                    146: bool Main_UnPauseEmulation(void) {
                    147:        if ( bEmulationActive )
                    148:                return false;
                    149: 
                    150:        bEmulationActive = true;
                    151:     host_pause_time(!(bEmulationActive));
                    152:     Screen_Pause(false);
                    153:     Sound_Pause(false);
                    154:     NextBus_Pause(false);
                    155: 
                    156:        if (bGrabMouse) {
                    157:                /* Grab mouse pointer again */
                    158:                SDL_SetRelativeMouseMode(SDL_TRUE);
                    159:         SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
                    160:     }
                    161:        return true;
                    162: }
                    163: 
                    164: /*-----------------------------------------------------------------------*/
                    165: /**
                    166:  * Optionally ask user whether to quit and set bQuitProgram accordingly
                    167:  */
                    168: void Main_RequestQuit(void) {
                    169:     if (ConfigureParams.Log.bConfirmQuit) {
                    170:                bQuitProgram = false;   /* if set true, dialog exits */
                    171:                bQuitProgram = DlgAlert_Query("All unsaved data will be lost.\nDo you really want to quit?");
                    172:        }
                    173:        else {
                    174:                bQuitProgram = true;
                    175:        }
                    176: 
                    177:        if (bQuitProgram) {
                    178:                /* Assure that CPU core shuts down */
                    179:                M68000_SetSpecial(SPCFLAG_BRK);
                    180:        }
                    181: }
                    182: 
                    183: /*-----------------------------------------------------------------------*/
                    184: /**
                    185:  * Since SDL_Delay and friends are very inaccurate on some systems, we have
                    186:  * to check if we can rely on this delay function.
                    187:  */
                    188: static void Main_CheckForAccurateDelays(void) {
                    189:        int nStartTicks, nEndTicks;
                    190: 
                    191:        /* Force a task switch now, so we have a longer timeslice afterwards */
                    192:        SDL_Delay(10);
                    193: 
                    194:        nStartTicks = SDL_GetTicks();
                    195:        SDL_Delay(1);
                    196:        nEndTicks = SDL_GetTicks();
                    197: 
                    198:        /* If the delay took longer than 10ms, we are on an inaccurate system! */
                    199:        bAccurateDelays = ((nEndTicks - nStartTicks) < 9);
                    200: 
                    201:        if (bAccurateDelays)
                    202:                Log_Printf(LOG_WARN, "Host system has accurate delays. (%d)\n", nEndTicks - nStartTicks);
                    203:        else
                    204:                Log_Printf(LOG_WARN, "Host system does not have accurate delays. (%d)\n", nEndTicks - nStartTicks);
                    205: }
                    206: 
                    207: 
                    208: /* ----------------------------------------------------------------------- */
                    209: /**
                    210:  * Set mouse pointer to new coordinates and set flag to ignore the mouse event
                    211:  * that is generated by SDL_WarpMouse().
                    212:  */
                    213: void Main_WarpMouse(int x, int y) {
                    214:     SDL_WarpMouseInWindow(sdlWindow, x, y); /* Set mouse pointer to new position */
                    215:        bIgnoreNextMouseMotion = true;          /* Ignore mouse motion event from SDL_WarpMouse */
                    216: }
                    217: 
                    218: 
                    219: /* ----------------------------------------------------------------------- */
                    220: /**
                    221:  * Handle mouse motion event.
                    222:  */
                    223: SDL_Event mymouse[100];
                    224: static void Main_HandleMouseMotion(SDL_Event *pEvent) {
                    225:        int dx, dy;
                    226:        int i,nb;
                    227: 
                    228:        dx = pEvent->motion.xrel;
                    229:        dy = pEvent->motion.yrel;
                    230: 
                    231:        /* get all mouse event to clean the queue and sum them */
                    232:        nb=SDL_PeepEvents(&mymouse[0], 100, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION);
                    233: 
                    234:        for (i=0;i<nb;i++) {
                    235:         dx += mymouse[i].motion.xrel;
                    236:         dy += mymouse[i].motion.yrel;
                    237:        }
                    238: 
                    239:        if (bGrabMouse) {
                    240:        Keymap_MouseMove(dx,dy,ConfigureParams.Mouse.fLinSpeedLocked,ConfigureParams.Mouse.fExpSpeedLocked);
                    241:        } else {
                    242:        Keymap_MouseMove(dx,dy,ConfigureParams.Mouse.fLinSpeedNormal,ConfigureParams.Mouse.fLinSpeedNormal);
                    243:        }
                    244: }
                    245: 
                    246: static int statusBarUpdate;
                    247: 
                    248: /* ----------------------------------------------------------------------- */
                    249: /**
                    250:  * SDL message handler.
                    251:  * Here we process the SDL events (keyboard, mouse, ...)
                    252:  */
                    253: void Main_EventHandler(void) {
                    254:     bool bContinueProcessing;
                    255:     SDL_Event event;
                    256:     int events;
                    257:     
                    258:     if(++statusBarUpdate > 400) {
                    259:         double vt;
                    260:         double rt;
                    261:         host_time(&rt, &vt);
                    262: #if ENABLE_TESTING
                    263:         fprintf(stderr, "[reports]");
                    264:         for(int i = 0; i < sizeof(reports)/sizeof(report_t); i++) {
                    265:             const char* msg = reports[i].report(rt, vt);
                    266:             if(msg[0]) fprintf(stderr, " %s:%s", reports[i].label, msg);
                    267:         }
                    268:         fprintf(stderr, "\n");
                    269: #else
                    270:         Main_Speed(rt, vt);
                    271: #endif
                    272:         Statusbar_UpdateInfo();
                    273:         statusBarUpdate = 0;
                    274:     }
                    275:     
                    276:     do {
                    277:         bContinueProcessing = false;
                    278:         
                    279:         /* check remote process control from different thread (e.g. i860) */
                    280:         switch(mainPauseEmulation) {
                    281:             case PAUSE_EMULATION:
                    282:                 mainPauseEmulation = PAUSE_NONE;
                    283:                 Main_PauseEmulation(true);
                    284:                 break;
                    285:             case UNPAUSE_EMULATION:
                    286:                 mainPauseEmulation = PAUSE_NONE;
                    287:                 Main_UnPauseEmulation();
                    288:                 break;
                    289:         }
                    290:         
                    291:         if (bEmulationActive) {
                    292:             double time_offset = host_real_time_offset() * 1000;
                    293:             if(time_offset > 10)
                    294:                 events = SDL_WaitEventTimeout(&event, time_offset);
                    295:             else
                    296:                 events = SDL_PollEvent(&event);
                    297:         }
                    298:         else {
                    299:             ShortCut_ActKey();
                    300:             /* last (shortcut) event activated emulation? */
                    301:             if ( bEmulationActive )
                    302:                 break;
                    303:             events = SDL_WaitEvent(&event);
                    304:         }
                    305:         if (!events) {
                    306:             /* no events -> if emulation is active or
                    307:              * user is quitting -> return from function.
                    308:              */
                    309:             continue;
                    310:         }
                    311:         switch (event.type) {
                    312:             case SDL_WINDOWEVENT:
                    313:                 if(event.window.event == SDL_WINDOWEVENT_CLOSE) {
                    314:                     SDL_WaitEventTimeout(&event, 100); // grab SDL_Quit if pending
                    315:                     Main_RequestQuit();
                    316:                 }
                    317:                 continue;
                    318: 
                    319:             case SDL_QUIT:
                    320:                 Main_RequestQuit();
                    321:                 break;
                    322:                 
                    323:             case SDL_MOUSEMOTION:               /* Read/Update internal mouse position */
                    324:                 Main_HandleMouseMotion(&event);
                    325:                 bContinueProcessing = false;
                    326:                 break;
                    327:                 
                    328:             case SDL_MOUSEBUTTONDOWN:
                    329:                 if (event.button.button == SDL_BUTTON_LEFT) {
                    330:                     if (ConfigureParams.Mouse.bEnableAutoGrab && !bGrabMouse) {
                    331:                         bGrabMouse = true;        /* Toggle flag */
                    332:                         
                    333:                         /* If we are in windowed mode, toggle the mouse cursor mode now: */
                    334:                         if (!bInFullScreen)
                    335:                         {
                    336:                             SDL_SetRelativeMouseMode(SDL_TRUE);
                    337:                             SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
                    338:                             Main_SetTitle(MOUSE_LOCK_MSG);
                    339:                         }
                    340:                     }
                    341:                     
                    342:                     Keymap_MouseDown(true);
                    343:                 }
                    344:                 else if (event.button.button == SDL_BUTTON_RIGHT)
                    345:                 {
                    346:                     Keymap_MouseDown(false);
                    347:                 }
                    348:                 break;
                    349:                 
                    350:             case SDL_MOUSEBUTTONUP:
                    351:                 if (event.button.button == SDL_BUTTON_LEFT) {
                    352:                     Keymap_MouseUp(true);
                    353:                 }
                    354:                 else if (event.button.button == SDL_BUTTON_RIGHT)
                    355:                 {
                    356:                     Keymap_MouseUp(false);
                    357:                 }
                    358:                 break;
                    359:                 
                    360:             case SDL_MOUSEWHEEL:
                    361:                 Keymap_MouseWheel(&event.wheel);
                    362:                 break;
                    363:                 
                    364:             case SDL_KEYDOWN:
                    365:                 if (event.key.repeat)
                    366:                     break;
                    367:                 
                    368:                 Keymap_KeyDown(&event.key.keysym);
                    369:                 break;
                    370:                 
                    371:             case SDL_KEYUP:
                    372:                 Keymap_KeyUp(&event.key.keysym);
                    373:                 break;
                    374:                 
                    375:                 
                    376:             default:
                    377:                 /* don't let unknown events delay event processing */
                    378:                 bContinueProcessing = true;
                    379:                 break;
                    380:         }
                    381:     } while (bContinueProcessing || !(bEmulationActive || bQuitProgram));
                    382: }
                    383: 
                    384: 
                    385: void Main_EventHandlerInterrupt() {
                    386:     CycInt_AcknowledgeInterrupt();
                    387:     Main_EventHandler();
                    388:     CycInt_AddRelativeInterruptUs((1000*1000)/200, 0, INTERRUPT_EVENT_LOOP); // poll events with 200 Hz
                    389: }
                    390: 
                    391: /*-----------------------------------------------------------------------*/
                    392: /**
                    393:  * Set Hatari window title. Use NULL for default
                    394:  */
                    395: void Main_SetTitle(const char *title) {
                    396:     if (title)
                    397:         SDL_SetWindowTitle(sdlWindow, title);
                    398:     else
                    399:         SDL_SetWindowTitle(sdlWindow, PROG_NAME);
                    400: }
                    401: 
                    402: /*-----------------------------------------------------------------------*/
                    403: /**
                    404:  * Initialise emulation
                    405:  */
                    406: static void Main_Init(void) {
                    407:        /* Open debug log file */
                    408:        if (!Log_Init()) {
                    409:                fprintf(stderr, "Logging/tracing initialization failed\n");
                    410:                exit(-1);
                    411:        }
                    412:        Log_Printf(LOG_INFO, PROG_NAME ", compiled on:  " __DATE__ ", " __TIME__ "\n");
                    413: 
                    414:        /* Init SDL's video subsystem. Note: Audio and joystick subsystems
                    415:           will be initialized later (failures there are not fatal). */
                    416:        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
                    417:        {
                    418:                fprintf(stderr, "Could not initialize the SDL library:\n %s\n", SDL_GetError() );
                    419:                exit(-1);
                    420:        }
                    421:        SDLGui_Init();
                    422:        Screen_Init();
                    423:        Main_SetTitle(NULL);
                    424:        DSP_Init();
                    425:        M68000_Init();                /* Init CPU emulation */
                    426:        Keymap_Init();
                    427: 
                    428:     /* call menu at startup */
                    429:     if (!File_Exists(sConfigFileName) || ConfigureParams.ConfigDialog.bShowConfigDialogAtStartup) {
                    430:         Dialog_DoProperty();
                    431:         if (bQuitProgram) {
                    432:             SDL_Quit();
                    433:             exit(-2);
                    434:         }
                    435:     }
                    436: 
                    437:     Dialog_CheckFiles();
                    438:     
                    439:     if (bQuitProgram) {
                    440:         SDL_Quit();
                    441:         exit(-2);
                    442:     }
                    443:     
                    444:     Reset_Cold();
                    445:     
                    446:        IoMem_Init();
                    447:        
                    448:     /* Start EventHandler */
                    449:     CycInt_AddRelativeInterruptUs(500*1000, 0, INTERRUPT_EVENT_LOOP);
                    450:     
                    451:        /* done as last, needs CPU & DSP running... */
                    452:        DebugUI_Init();
                    453: }
                    454: 
                    455: 
                    456: /*-----------------------------------------------------------------------*/
                    457: /**
                    458:  * Un-Initialise emulation
                    459:  */
                    460: static void Main_UnInit(void) {
                    461:        Screen_ReturnFromFullScreen();
                    462:        IoMem_UnInit();
                    463:        SDLGui_UnInit();
                    464:        Screen_UnInit();
                    465:        Exit680x0();
                    466: 
                    467:        /* SDL uninit: */
                    468:        SDL_Quit();
                    469: 
                    470:        /* Close debug log file */
                    471:        Log_UnInit();
                    472: }
                    473: 
                    474: 
                    475: /*-----------------------------------------------------------------------*/
                    476: /**
                    477:  * Load initial configuration file(s)
                    478:  */
                    479: static void Main_LoadInitialConfig(void) {
                    480:        char *psGlobalConfig;
                    481: 
                    482:        psGlobalConfig = malloc(FILENAME_MAX);
                    483:        if (psGlobalConfig)
                    484:        {
                    485: #if defined(__AMIGAOS4__)
                    486:                strncpy(psGlobalConfig, CONFDIR"previous.cfg", FILENAME_MAX);
                    487: #else
                    488:                snprintf(psGlobalConfig, FILENAME_MAX, CONFDIR"%cprevious.cfg", PATHSEP);
                    489: #endif
                    490:                /* Try to load the global configuration file */
                    491:                Configuration_Load(psGlobalConfig);
                    492: 
                    493:                free(psGlobalConfig);
                    494:        }
                    495: 
                    496:        /* Now try the users configuration file */
                    497:        Configuration_Load(NULL);
                    498: }
                    499: 
                    500: /*-----------------------------------------------------------------------*/
                    501: /**
                    502:  * Set TOS etc information and initial help message
                    503:  */
                    504: static void Main_StatusbarSetup(void) {
                    505:        const char *name = NULL;
                    506:        SDL_Keycode key;
                    507: 
                    508:        key = ConfigureParams.Shortcut.withoutModifier[SHORTCUT_OPTIONS];
                    509:        if (!key)
                    510:                key = ConfigureParams.Shortcut.withModifier[SHORTCUT_OPTIONS];
                    511:        if (key)
                    512:                name = SDL_GetKeyName(key);
                    513:        if (name)
                    514:        {
                    515:                char message[24], *keyname;
                    516: #ifdef _MUDFLAP
                    517:                __mf_register(name, 32, __MF_TYPE_GUESS, "SDL keyname");
                    518: #endif
                    519:                keyname = Str_ToUpper(strdup(name));
                    520:                snprintf(message, sizeof(message), "Press %s for Options", keyname);
                    521:                free(keyname);
                    522: 
                    523:                Statusbar_AddMessage(message, 6000);
                    524:        }
                    525:        /* update information loaded by Main_Init() */
                    526:        Statusbar_UpdateInfo();
                    527: }
                    528: 
                    529: #ifdef WIN32
                    530:        extern void Win_OpenCon(void);
                    531: #endif
                    532: 
                    533: /*-----------------------------------------------------------------------*/
                    534: /**
                    535:  * Set signal handlers to catch signals
                    536:  */
                    537: static void Main_SetSignalHandlers(void) {
                    538: #ifndef _WIN32
                    539:     signal(SIGPIPE, SIG_IGN);
                    540: #endif
                    541:     signal(SIGFPE, SIG_IGN);
                    542: }
                    543: 
                    544: 
                    545: /*-----------------------------------------------------------------------*/
                    546: /**
                    547:  * Main
                    548:  * 
                    549:  * Note: 'argv' cannot be declared const, MinGW would then fail to link.
                    550:  */
                    551: int main(int argc, char *argv[]) {
                    552:        /* Generate random seed */
                    553:        srand(time(NULL));
                    554:     
                    555:     /* Set signal handlers */
                    556:     Main_SetSignalHandlers();
                    557: 
                    558:        /* Initialize directory strings */
                    559:        Paths_Init(argv[0]);
                    560: 
                    561:        /* Set default configuration values: */
                    562:        Configuration_SetDefault();
                    563: 
                    564:        /* Now load the values from the configuration file */
                    565:        Main_LoadInitialConfig();
                    566:     
                    567: #if 0 /* FIXME: This sometimes causes exits when starting from application bundles */
                    568:        /* Check for any passed parameters */
                    569:        if (!Opt_ParseParameters(argc, (const char * const *)argv))
                    570:        {
                    571:                return 1;
                    572:        }
                    573: #endif
                    574:        /* monitor type option might require "reset" -> true */
                    575:        Configuration_Apply(true);
                    576: 
                    577: #ifdef WIN32
                    578:        Win_OpenCon();
                    579: #endif
                    580: 
                    581:        /* Needed on maemo but useful also with normal X11 window managers
                    582:         * for window grouping when you have multiple Hatari SDL windows open
                    583:         */
                    584: #if HAVE_SETENV
                    585:        setenv("SDL_VIDEO_X11_WMCLASS", "previous", 1);
                    586: #endif
                    587: 
                    588:        /* Init emulator system */
                    589:        Main_Init();
                    590: 
                    591:        /* Set initial Statusbar information */
                    592:        Main_StatusbarSetup();
                    593:        
                    594:        /* Check if SDL_Delay is accurate */
                    595:        Main_CheckForAccurateDelays();
                    596: 
                    597: 
                    598:        /* Run emulation */
                    599:        Main_UnPauseEmulation();
                    600:        M68000_Start();                 /* Start emulation */
                    601: 
                    602: 
                    603:        /* Un-init emulation system */
                    604:        Main_UnInit();
                    605: 
                    606:        return 0;
                    607: }

unix.superglobalmegacorp.com

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