예제 #1
0
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;
	}
}
예제 #2
0
bool Engine::shouldQuit() {
	Common::EventManager *eventMan = g_system->getEventManager();
	return (eventMan->shouldQuit() || eventMan->shouldRTL());
}
예제 #3
0
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
}