void MainLoop() override { bool fullscreen = SConfig::GetInstance().bFullscreen; int last_window_width = SConfig::GetInstance().iRenderWindowWidth; int last_window_height = SConfig::GetInstance().iRenderWindowHeight; if (fullscreen) { rendererIsFullscreen = X11Utils::ToggleFullscreen(dpy, win); #if defined(HAVE_XRANDR) && HAVE_XRANDR XRRConfig->ToggleDisplayMode(True); #endif } // The actual loop while (s_running.IsSet()) { if (s_shutdown_requested.TestAndClear()) { const auto ios = IOS::HLE::GetIOS(); const auto stm = ios ? ios->GetDeviceByName("/dev/stm/eventhook") : nullptr; if (!s_tried_graceful_shutdown.IsSet() && stm && std::static_pointer_cast<IOS::HLE::Device::STMEventHook>(stm)->HasHookInstalled()) { ProcessorInterface::PowerButton_Tap(); s_tried_graceful_shutdown.Set(); } else { s_running.Clear(); } } XEvent event; KeySym key; for (int num_events = XPending(dpy); num_events > 0; num_events--) { XNextEvent(dpy, &event); switch (event.type) { case KeyPress: key = XLookupKeysym((XKeyEvent*)&event, 0); if (key == XK_Escape) { if (Core::GetState() == Core::State::Running) { if (SConfig::GetInstance().bHideCursor) XUndefineCursor(dpy, win); Core::SetState(Core::State::Paused); } else { if (SConfig::GetInstance().bHideCursor) XDefineCursor(dpy, win, blankCursor); Core::SetState(Core::State::Running); } } else if ((key == XK_Return) && (event.xkey.state & Mod1Mask)) { fullscreen = !fullscreen; X11Utils::ToggleFullscreen(dpy, win); #if defined(HAVE_XRANDR) && HAVE_XRANDR XRRConfig->ToggleDisplayMode(fullscreen); #endif } else if (key >= XK_F1 && key <= XK_F8) { int slot_number = key - XK_F1 + 1; if (event.xkey.state & ShiftMask) State::Save(slot_number); else State::Load(slot_number); } else if (key == XK_F9) Core::SaveScreenShot(); else if (key == XK_F11) State::LoadLastSaved(); else if (key == XK_F12) { if (event.xkey.state & ShiftMask) State::UndoLoadState(); else State::UndoSaveState(); } break; case FocusIn: rendererHasFocus = true; if (SConfig::GetInstance().bHideCursor && Core::GetState() != Core::State::Paused) XDefineCursor(dpy, win, blankCursor); break; case FocusOut: rendererHasFocus = false; if (SConfig::GetInstance().bHideCursor) XUndefineCursor(dpy, win); break; case ClientMessage: if ((unsigned long)event.xclient.data.l[0] == XInternAtom(dpy, "WM_DELETE_WINDOW", False)) s_shutdown_requested.Set(); break; case ConfigureNotify: { if (last_window_width != event.xconfigure.width || last_window_height != event.xconfigure.height) { last_window_width = event.xconfigure.width; last_window_height = event.xconfigure.height; // We call Renderer::ChangeSurface here to indicate the size has changed, // but pass the same window handle. This is needed for the Vulkan backend, // otherwise it cannot tell that the window has been resized on some drivers. if (g_renderer) g_renderer->ChangeSurface(s_window_handle); } } break; } } if (!fullscreen) { Window winDummy; unsigned int borderDummy, depthDummy; XGetGeometry(dpy, win, &winDummy, &SConfig::GetInstance().iRenderWindowXPos, &SConfig::GetInstance().iRenderWindowYPos, (unsigned int*)&SConfig::GetInstance().iRenderWindowWidth, (unsigned int*)&SConfig::GetInstance().iRenderWindowHeight, &borderDummy, &depthDummy); rendererIsFullscreen = false; } Core::HostDispatchJobs(); usleep(100000); } }