void GuiManager::runLoop() { Dialog * const activeDialog = getTopDialog(); bool didSaveState = false; int button; uint32 time; if (activeDialog == 0) return; if (!_stateIsSaved) { saveState(); _theme->enable(); didSaveState = true; _useStdCursor = !_theme->ownCursor(); if (_useStdCursor) setupCursor(); // _theme->refresh(); _redrawStatus = kRedrawFull; redraw(); } _lastMousePosition.x = _lastMousePosition.y = -1; _lastMousePosition.time = 0; Common::EventManager *eventMan = _system->getEventManager(); uint32 lastRedraw = 0; const uint32 waitTime = 1000 / 45; bool tooltipCheck = false; while (!_dialogStack.empty() && activeDialog == getTopDialog() && !eventMan->shouldQuit()) { redraw(); // Don't "tickle" the dialog until the theme has had a chance // to re-allocate buffers in case of a scaler change. activeDialog->handleTickle(); if (_useStdCursor) animateCursor(); // _theme->updateScreen(); // _system->updateScreen(); if (lastRedraw + waitTime < _system->getMillis()) { _theme->updateScreen(); _system->updateScreen(); lastRedraw = _system->getMillis(); } Common::Event event; while (eventMan->pollEvent(event)) { // The top dialog can change during the event loop. In that case, flush all the // dialog-related events since they were probably generated while the old dialog // was still visible, and therefore not intended for the new one. // // This hopefully fixes strange behavior/crashes with pop-up widgets. (Most easily // triggered in 3x mode or when running ScummVM under Valgrind.) if (activeDialog != getTopDialog() && event.type != Common::EVENT_SCREEN_CHANGED) continue; Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); switch (event.type) { case Common::EVENT_KEYDOWN: activeDialog->handleKeyDown(event.kbd); break; case Common::EVENT_KEYUP: activeDialog->handleKeyUp(event.kbd); break; case Common::EVENT_MOUSEMOVE: activeDialog->handleMouseMoved(mouse.x, mouse.y, 0); if (mouse.x != _lastMousePosition.x || mouse.y != _lastMousePosition.y) { _lastMousePosition.x = mouse.x; _lastMousePosition.y = mouse.y; _lastMousePosition.time = _system->getMillis(); } tooltipCheck = true; break; // We don't distinguish between mousebuttons (for now at least) case Common::EVENT_LBUTTONDOWN: case Common::EVENT_RBUTTONDOWN: button = (event.type == Common::EVENT_LBUTTONDOWN ? 1 : 2); time = _system->getMillis(); if (_lastClick.count && (time < _lastClick.time + kDoubleClickDelay) && ABS(_lastClick.x - event.mouse.x) < 3 && ABS(_lastClick.y - event.mouse.y) < 3) { _lastClick.count++; } else { _lastClick.x = event.mouse.x; _lastClick.y = event.mouse.y; _lastClick.count = 1; } _lastClick.time = time; activeDialog->handleMouseDown(mouse.x, mouse.y, button, _lastClick.count); break; case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONUP: button = (event.type == Common::EVENT_LBUTTONUP ? 1 : 2); activeDialog->handleMouseUp(mouse.x, mouse.y, button, _lastClick.count); break; case Common::EVENT_WHEELUP: activeDialog->handleMouseWheel(mouse.x, mouse.y, -1); break; case Common::EVENT_WHEELDOWN: activeDialog->handleMouseWheel(mouse.x, mouse.y, 1); break; case Common::EVENT_SCREEN_CHANGED: screenChange(); break; default: #ifdef ENABLE_KEYMAPPER activeDialog->handleOtherEvent(event); #endif break; } if (lastRedraw + waitTime < _system->getMillis()) { _theme->updateScreen(); _system->updateScreen(); lastRedraw = _system->getMillis(); } } if (tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis()) { Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y); if (wdg && wdg->getTooltip()) { Tooltip *tooltip = new Tooltip(); tooltip->setup(activeDialog, wdg, _lastMousePosition.x, _lastMousePosition.y); tooltip->runModal(); delete tooltip; } } // Delay for a moment _system->delayMillis(10); } // WORKAROUND: When quitting we might not properly close the dialogs on // the dialog stack, thus we do this here to avoid any problems. // This is most noticable in bug #3481395 "LAUNCHER: Can't quit from unsupported game dialog". // It seems that Dialog::runModal never removes the dialog from the dialog // stack, thus if the dialog does not call Dialog::close to close itself // it will never be removed. Since we can have multiple run loops being // called we cannot rely on catching EVENT_QUIT in the event loop above, // since it would only catch it for the top run loop. if (eventMan->shouldQuit() && activeDialog == getTopDialog()) getTopDialog()->close(); if (didSaveState) { _theme->disable(); restoreState(); _useStdCursor = false; } }
bool Engine::shouldQuit() { Common::EventManager *eventMan = g_system->getEventManager(); return (eventMan->shouldQuit() || eventMan->shouldRTL()); }
void GuiManager::runLoop() { Dialog * const activeDialog = getTopDialog(); bool didSaveState = false; if (activeDialog == 0) return; #ifdef ENABLE_EVENTRECORDER // Suspend recording while GUI is shown g_eventRec.suspendRecording(); #endif if (!_stateIsSaved) { saveState(); _theme->enable(); didSaveState = true; _useStdCursor = !_theme->ownCursor(); if (_useStdCursor) setupCursor(); // _theme->refresh(); _redrawStatus = kRedrawFull; redraw(); } Common::EventManager *eventMan = _system->getEventManager(); uint32 lastRedraw = 0; const uint32 waitTime = 1000 / 60; while (!_dialogStack.empty() && activeDialog == getTopDialog() && !eventMan->shouldQuit()) { redraw(); // Don't "tickle" the dialog until the theme has had a chance // to re-allocate buffers in case of a scaler change. activeDialog->handleTickle(); if (_useStdCursor) animateCursor(); // _theme->updateScreen(); // _system->updateScreen(); if (lastRedraw + waitTime < _system->getMillis(true)) { lastRedraw = _system->getMillis(true); _theme->updateScreen(); _system->updateScreen(); } Common::Event event; while (eventMan->pollEvent(event)) { // We will need to check whether the screen changed while polling // for an event here. While we do send EVENT_SCREEN_CHANGED // whenever this happens we still cannot be sure that we get such // an event immediately. For example, we might have an mouse move // event queued before an screen changed event. In some rare cases // this would make the GUI redraw (with the code a few lines // below) when it is not yet updated for new overlay dimensions. // As a result ScummVM would crash because it tries to copy data // outside the actual overlay screen. if (event.type != Common::EVENT_SCREEN_CHANGED) { checkScreenChange(); } // The top dialog can change during the event loop. In that case, flush all the // dialog-related events since they were probably generated while the old dialog // was still visible, and therefore not intended for the new one. // // This hopefully fixes strange behavior/crashes with pop-up widgets. (Most easily // triggered in 3x mode or when running ScummVM under Valgrind.) if (activeDialog != getTopDialog() && event.type != Common::EVENT_SCREEN_CHANGED) { processEvent(event, getTopDialog()); continue; } processEvent(event, activeDialog); if (lastRedraw + waitTime < _system->getMillis(true)) { lastRedraw = _system->getMillis(true); _theme->updateScreen(); _system->updateScreen(); } } if (_lastMousePosition.time + kTooltipDelay < _system->getMillis(true)) { Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y); if (wdg && wdg->hasTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) { Tooltip *tooltip = new Tooltip(); tooltip->setup(activeDialog, wdg, _lastMousePosition.x, _lastMousePosition.y); tooltip->runModal(); delete tooltip; } } // Delay for a moment _system->delayMillis(10); } // WORKAROUND: When quitting we might not properly close the dialogs on // the dialog stack, thus we do this here to avoid any problems. // This is most noticable in bug #3481395 "LAUNCHER: Can't quit from unsupported game dialog". // It seems that Dialog::runModal never removes the dialog from the dialog // stack, thus if the dialog does not call Dialog::close to close itself // it will never be removed. Since we can have multiple run loops being // called we cannot rely on catching EVENT_QUIT in the event loop above, // since it would only catch it for the top run loop. if (eventMan->shouldQuit() && activeDialog == getTopDialog()) getTopDialog()->close(); if (didSaveState) { _theme->disable(); restoreState(); _useStdCursor = false; } #ifdef ENABLE_EVENTRECORDER // Resume recording once GUI is shown g_eventRec.resumeRecording(); #endif }