From ad4da764df66d98b39463e63e7242de5ec3df077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 2 Feb 2026 11:45:46 +0100 Subject: [PATCH] Rework the internal API for applying the fullscreen state. Fixes. --- Common/System/Request.cpp | 2 +- Common/System/Request.h | 5 +-- Common/System/System.h | 2 +- SDL/CocoaBarItems.mm | 2 +- SDL/SDLMain.cpp | 26 ++++-------- UI/EmuScreen.cpp | 4 +- UI/GameSettingsScreen.cpp | 19 ++++----- UI/MainScreen.cpp | 20 ++++----- UI/MainScreen.h | 1 - UI/NativeApp.cpp | 2 - Windows/InputDevice.h | 2 +- Windows/MainWindow.cpp | 85 ++++++++++++++++++++------------------ Windows/MainWindow.h | 4 +- Windows/MainWindowMenu.cpp | 3 +- Windows/main.cpp | 10 +---- 15 files changed, 85 insertions(+), 102 deletions(-) diff --git a/Common/System/Request.cpp b/Common/System/Request.cpp index 739b61b6e0..93ba687cbe 100644 --- a/Common/System/Request.cpp +++ b/Common/System/Request.cpp @@ -35,7 +35,7 @@ const char *RequestTypeAsString(SystemRequestType type) { case SystemRequestType::COPY_TO_CLIPBOARD: return "COPY_TO_CLIPBOARD"; case SystemRequestType::SHARE_TEXT: return "SHARE_TEXT"; case SystemRequestType::SET_WINDOW_TITLE: return "SET_WINDOW_TITLE"; - case SystemRequestType::TOGGLE_FULLSCREEN_STATE: return "TOGGLE_FULLSCREEN_STATE"; + case SystemRequestType::APPLY_FULLSCREEN_STATE: return "SET_FULLSCREEN_STATE"; case SystemRequestType::GRAPHICS_BACKEND_FAILED_ALERT: return "GRAPHICS_BACKEND_FAILED_ALERT"; case SystemRequestType::CREATE_GAME_SHORTCUT: return "CREATE_GAME_SHORTCUT"; case SystemRequestType::SHOW_FILE_IN_FOLDER: return "SHOW_FILE_IN_FOLDER"; diff --git a/Common/System/Request.h b/Common/System/Request.h index 8c2297ec32..281e0bc0e9 100644 --- a/Common/System/Request.h +++ b/Common/System/Request.h @@ -143,9 +143,8 @@ inline void System_RecreateActivity() { g_requestManager.MakeSystemRequest(SystemRequestType::RECREATE_ACTIVITY, NO_REQUESTER_TOKEN, nullptr, nullptr, "", "", 0); } -// The design is a little weird, just a holdover from the old message. Can either toggle or set to on or off. -inline void System_ToggleFullscreenState(std::string_view param) { - g_requestManager.MakeSystemRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, NO_REQUESTER_TOKEN, nullptr, nullptr, param, "", 0); +inline void System_ApplyFullscreenState() { + g_requestManager.MakeSystemRequest(SystemRequestType::APPLY_FULLSCREEN_STATE, NO_REQUESTER_TOKEN, nullptr, nullptr, "", "", 0); } inline void System_GraphicsBackendFailedAlert(std::string_view param) { diff --git a/Common/System/System.h b/Common/System/System.h index 88e7e1ac3d..ac4414d309 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -79,7 +79,7 @@ enum class SystemRequestType { COPY_TO_CLIPBOARD, SHARE_TEXT, SET_WINDOW_TITLE, - TOGGLE_FULLSCREEN_STATE, + APPLY_FULLSCREEN_STATE, GRAPHICS_BACKEND_FAILED_ALERT, CREATE_GAME_SHORTCUT, SHOW_FILE_IN_FOLDER, diff --git a/SDL/CocoaBarItems.mm b/SDL/CocoaBarItems.mm index 7a04794383..74ea3d28a6 100644 --- a/SDL/CocoaBarItems.mm +++ b/SDL/CocoaBarItems.mm @@ -549,7 +549,7 @@ TOGGLE_METHOD_INVERSE(BreakOnLoad, g_Config.bAutoRun) TOGGLE_METHOD(IgnoreIllegalRWs, g_Config.bIgnoreBadMemAccess) TOGGLE_METHOD(AutoFrameSkip, g_Config.bAutoFrameSkip, g_Config.UpdateAfterSettingAutoFrameSkip()) TOGGLE_METHOD(SoftwareRendering, g_Config.bSoftwareRendering) -TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_MakeRequest(SystemRequestType::TOGGLE_FULLSCREEN_STATE, 0, g_Config.bFullScreen ? "1" : "0", "", 3, 0)) +TOGGLE_METHOD(FullScreen, g_Config.bFullScreen, System_SetFullscreenState(!g_Config.bFullScreen)); // TOGGLE_METHOD(VSync, g_Config.bVSync) #undef TOGGLE_METHOD diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 0a843845c5..2af8dd4d16 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -113,8 +113,7 @@ double g_audioStartTime = 0.0; static std::mutex g_mutexWindow; struct WindowState { std::string title; - bool toggleFullScreenNextFrame; - int toggleFullScreenType; + bool applyFullScreenNextFrame; bool clipboardDataAvailable; std::string clipboardString; bool update; @@ -429,19 +428,12 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string return true; } #endif - case SystemRequestType::TOGGLE_FULLSCREEN_STATE: + case SystemRequestType::APPLY_FULLSCREEN_STATE: { + g_Config.bFullScreen = (param3 != 0); std::lock_guard guard(g_mutexWindow); g_windowState.update = true; - g_windowState.toggleFullScreenNextFrame = true; - if (param1 == "1") { - g_windowState.toggleFullScreenType = 1; - } else if (param1 == "0") { - g_windowState.toggleFullScreenType = 0; - } else { - // Just toggle. - g_windowState.toggleFullScreenType = -1; - } + g_windowState.applyFullScreenNextFrame = true; return true; } case SystemRequestType::SET_WINDOW_TITLE: @@ -820,13 +812,11 @@ static float parseFloat(const char *str) { void UpdateWindowState(SDL_Window *window) { SDL_SetWindowTitle(window, g_windowState.title.c_str()); - if (g_windowState.toggleFullScreenNextFrame) { - g_windowState.toggleFullScreenNextFrame = false; + if (g_windowState.applyFullScreenNextFrame) { + g_windowState.applyFullScreenNextFrame = false; Uint32 window_flags = SDL_GetWindowFlags(window); - if (g_windowState.toggleFullScreenType == -1) { - window_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP; - } else if (g_windowState.toggleFullScreenType == 1) { + if (g_Config.bFullScreen) { window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } else { window_flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP; @@ -1052,7 +1042,7 @@ static void ProcessSDLEvent(SDL_Window *window, const SDL_Event &event, InputSta if (k == SDLK_F11) { #if !defined(MOBILE_DEVICE) g_Config.bFullScreen = !g_Config.bFullScreen; - System_ToggleFullscreenState(""); + System_applyFullscreenState(""); #endif } */ diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 42b3bf834a..fed06667c6 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -971,7 +971,9 @@ void EmuScreen::ProcessVKey(VirtKey virtKey) { break; case VIRTKEY_TOGGLE_FULLSCREEN: - System_ToggleFullscreenState(""); + // TODO: Limit to platforms that can support fullscreen. + g_Config.bFullScreen = !g_Config.bFullScreen; + System_ApplyFullscreenState(); break; case VIRTKEY_TOGGLE_TOUCH_CONTROLS: diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 1c5975b6ac..9cb812e3a1 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -413,13 +413,18 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) if (deviceType != DEVICE_TYPE_VR) { #if !defined(MOBILE_DEVICE) - graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); + CheckBox *fullscreenCheckbox = graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen", "Full Screen"))); + fullscreenCheckbox->OnClick.Add([](UI::EventParams &e) { + System_ApplyFullscreenState(); + }); if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) { - CheckBox *fullscreenMulti = new CheckBox(&g_Config.bFullScreenMulti, gr->T("Use all displays")); + CheckBox *fullscreenMulti = graphicsSettings->Add(new CheckBox(&g_Config.bFullScreenMulti, gr->T("Use all displays"))); fullscreenMulti->SetEnabledFunc([] { return g_Config.bFullScreen; }); - graphicsSettings->Add(fullscreenMulti)->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenMultiChange); + fullscreenMulti->OnClick.Add([](UI::EventParams &e) { + System_ApplyFullscreenState(); + }); } #endif @@ -1621,14 +1626,6 @@ void GameSettingsScreen::OnChangeBackground(UI::EventParams &e) { // Change to a browse or clear button. } -void GameSettingsScreen::OnFullscreenChange(UI::EventParams &e) { - System_ToggleFullscreenState(g_Config.bFullScreen ? "1" : "0"); -} - -void GameSettingsScreen::OnFullscreenMultiChange(UI::EventParams &e) { - System_ToggleFullscreenState(g_Config.bFullScreen ? "1" : "0"); -} - void GameSettingsScreen::dialogFinished(const Screen *dialog, DialogResult result) { bool recreate = false; if (result == DialogResult::DR_OK) { diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index fa25a16c33..3ab1dbe324 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -1431,7 +1431,15 @@ void MainScreen::CreateViews() { ImageID icon(g_Config.bFullScreen ? "I_RESTORE" : "I_FULLSCREEN"); fullscreenButton_ = logo->Add(new Button(gr->T("FullScreen", "Full Screen"), icon, new AnchorLayoutParams(48, 48, NONE, 0, 0, NONE, Centering::None))); fullscreenButton_->SetIgnoreText(true); - fullscreenButton_->OnClick.Handle(this, &MainScreen::OnFullScreenToggle); + fullscreenButton_->OnClick.Add([this](UI::EventParams &e) { + if (fullscreenButton_) { + fullscreenButton_->SetImageID(ImageID(!g_Config.bFullScreen ? "I_RESTORE" : "I_FULLSCREEN")); + } +#if !defined(MOBILE_DEVICE) + g_Config.bFullScreen = !g_Config.bFullScreen; + System_ApplyFullscreenState(); +#endif + }); #endif rightColumnItems->Add(logo); @@ -1510,16 +1518,6 @@ void MainScreen::OnLoadFile(UI::EventParams &e) { } } -void MainScreen::OnFullScreenToggle(UI::EventParams &e) { - if (fullscreenButton_) { - fullscreenButton_->SetImageID(ImageID(!g_Config.bFullScreen ? "I_RESTORE" : "I_FULLSCREEN")); - } -#if !defined(MOBILE_DEVICE) - g_Config.bFullScreen = !g_Config.bFullScreen; - System_ToggleFullscreenState(""); -#endif -} - void MainScreen::DrawBackground(UIContext &dc) { if (highlightedGamePath_.empty() && prevHighlightedGamePath_.empty()) { return; diff --git a/UI/MainScreen.h b/UI/MainScreen.h index f27ee7d73f..3f9f556e8f 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -160,7 +160,6 @@ protected: void OnForums(UI::EventParams &e); void OnExit(UI::EventParams &e); void OnAllowStorage(UI::EventParams &e); - void OnFullScreenToggle(UI::EventParams &e); UI::TabHolder *tabHolder_ = nullptr; UI::Button *fullscreenButton_ = nullptr; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index b39e55a5de..68065ef606 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -582,7 +582,6 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch if (!strcmp(argv[i], "--fullscreen")) { g_Config.DoNotSaveSetting(&g_Config.bFullScreen); g_Config.bFullScreen = true; - System_ToggleFullscreenState("1"); } if (!strncmp(argv[i], "--root=", strlen("--root=")) && strlen(argv[i]) > strlen("--root=")) { g_Config.mountRoot = Path(argv[i] + strlen("--root=")); @@ -590,7 +589,6 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch if (!strcmp(argv[i], "--windowed")) { g_Config.DoNotSaveSetting(&g_Config.bFullScreen); g_Config.bFullScreen = false; - System_ToggleFullscreenState("0"); } if (!strcmp(argv[i], "--touchscreentest")) gotoTouchScreenTest = true; diff --git a/Windows/InputDevice.h b/Windows/InputDevice.h index d29bc93d64..184990a794 100644 --- a/Windows/InputDevice.h +++ b/Windows/InputDevice.h @@ -17,9 +17,9 @@ #pragma once -#include #include #include +#include #include #include "Common/CommonTypes.h" diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index be11fcead9..4016a8cff4 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -137,6 +137,19 @@ inline int WindowSizeStateToShowCmd(const WindowSizeState windowSizeState) { } } +static const char *WindowSizeStateToString(const WindowSizeState state) { + switch (state) { + case WindowSizeState::Normal: + return "Normal"; + case WindowSizeState::Minimized: + return "Minimized"; + case WindowSizeState::Maximized: + return "Maximized"; + default: + return "Unknown"; + } +} + namespace MainWindow { static HWND hwndMain; static TouchInputHandler touchHandler; @@ -161,6 +174,7 @@ namespace MainWindow { // gross hack bool noFocusPause = false; // TOGGLE_PAUSE state to override pause on lost focus + static bool trapMouse = true; // Handles some special cases(alt+tab, win menu) when game is running and mouse is confined static constexpr wchar_t *szWindowClass = L"PPSSPPWnd"; @@ -267,7 +281,7 @@ namespace MainWindow { } } - static void HandleSizeChange(int newSizingType) { + static void HandleSizeChange() { Native_NotifyWindowHidden(false); if (!g_Config.bPauseWhenMinimized) { System_PostUIMessage(UIMessage::WINDOW_MINIMIZED, "false"); @@ -303,6 +317,11 @@ namespace MainWindow { const bool isCurrentlyFullscreen = !(prevStyle & WS_OVERLAPPEDWINDOW); if (goFullscreen && !isCurrentlyFullscreen) { + INFO_LOG(Log::System, "ApplyFullscreenState: Entering fullscreen from %s mode at %dx%d+%d+%d", + WindowSizeStateToString((WindowSizeState)g_Config.iWindowSizeState), + g_Config.iWindowWidth, g_Config.iWindowHeight, + g_Config.iWindowX, g_Config.iWindowY); + // Transitioning to Fullscreen WINDOWPLACEMENT wp = {sizeof(WINDOWPLACEMENT)}; if (GetWindowPlacement(hWnd, &wp)) { @@ -327,7 +346,6 @@ namespace MainWindow { totalX, totalY, totalWidth, totalHeight, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - g_Config.bFullScreen = true; } else { MONITORINFO mi = {sizeof(mi)}; if (GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &mi)) { @@ -340,11 +358,14 @@ namespace MainWindow { mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - - g_Config.bFullScreen = true; } } } else if (!goFullscreen && isCurrentlyFullscreen) { + INFO_LOG(Log::System, "ApplyFullscreenState: Exiting fullscreen to %s mode at %dx%d+%d+%d", + WindowSizeStateToString((WindowSizeState)g_Config.iWindowSizeState), + g_Config.iWindowWidth, g_Config.iWindowHeight, + g_Config.iWindowX, g_Config.iWindowY); + // Transitioning to Windowed SetWindowLong(hWnd, GWL_STYLE, prevStyle | WS_OVERLAPPEDWINDOW); SetMenu(hWnd, g_hMenu); @@ -358,8 +379,6 @@ namespace MainWindow { SetWindowPlacement(hWnd, &wp); SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); - - g_Config.bFullScreen = false; } inFullscreenResize = false; @@ -799,8 +818,8 @@ namespace MainWindow { // Then never erase, let the OpenGL drawing take care of everything. return 1; - case WM_USER_TOGGLE_FULLSCREEN: - ApplyFullscreenState(hwndMain, wParam ? true : false); + case WM_USER_APPLY_FULLSCREEN: + ApplyFullscreenState(hwndMain, g_Config.bFullScreen); break; case WM_DISPLAYCHANGE: @@ -819,12 +838,21 @@ namespace MainWindow { case WM_WINDOWPOSCHANGED: { + // Handling this means that WM_SIZE and WM_MOVE won't be sent, except once during + // window creation for some reason. const WINDOWPOS *pos = reinterpret_cast(lParam); if (!pos) { // Uh? return DefWindowProc(hWnd, message, wParam, lParam); } const bool sizeChanged = !(pos->flags & SWP_NOSIZE); + + WINDOWPLACEMENT wp{sizeof(wp)}; + GetWindowPlacement(hWnd, &wp); + if (!g_Config.bFullScreen) { + g_Config.iWindowSizeState = (int)ShowCmdToWindowSizeState(wp.showCmd); + } + if (sizeChanged) { if (g_Config.bFullScreen) { MONITORINFO mi = {sizeof(mi)}; @@ -848,8 +876,9 @@ namespace MainWindow { } } } - // This means that WM_SIZE and WM_MOVE won't be sent. - HandleSizeChange(SIZE_RESTORED); + if (!inResizeMove) { + HandleSizeChange(); + } } return 0; } @@ -860,32 +889,7 @@ namespace MainWindow { case WM_EXITSIZEMOVE: inResizeMove = false; - HandleSizeChange(SIZE_RESTORED); - break; - - case WM_SIZE: - switch (wParam) { - case SIZE_RESTORED: - case SIZE_MAXIMIZED: - if (!inResizeMove) { - HandleSizeChange(wParam); - } - if (g_wasMinimized) { - System_PostUIMessage(UIMessage::WINDOW_RESTORED, "true"); - g_wasMinimized = false; - } - break; - - case SIZE_MINIMIZED: - Native_NotifyWindowHidden(true); - if (!g_Config.bPauseWhenMinimized) { - System_PostUIMessage(UIMessage::WINDOW_MINIMIZED, "true"); - } - g_wasMinimized = true; - break; - default: - break; - } + HandleSizeChange(); break; // Wheel events have to stay in WndProc for compatibility with older Windows(7). See #12156 @@ -1166,7 +1170,8 @@ namespace MainWindow { const float dy = lastMouseDownY - y; const float distSq = dx * dx + dy * dy; if (distSq < 3.0f*3.0f && !g_Config.bShowTouchControls && !g_Config.bShowImDebugger && !g_Config.bMouseControl && GetUIState() == UISTATE_INGAME && g_Config.bFullscreenOnDoubleclick) { - SendToggleFullscreen(!g_Config.bFullScreen); + g_Config.bFullScreen = !g_Config.bFullScreen; + SendApplyFullscreenState(); } lastMouseDownTime = 0.0; } else { @@ -1276,12 +1281,12 @@ namespace MainWindow { } } - void SendToggleFullscreen(bool fullscreen) { - PostMessage(hwndMain, WM_USER_TOGGLE_FULLSCREEN, fullscreen, 0); + void SendApplyFullscreenState() { + PostMessage(hwndMain, WM_USER_APPLY_FULLSCREEN, 0, 0); } void RunCallbackInWndProc(void (*callback)(void *, void *), void *userdata) { PostMessage(hwndMain, WM_USER_RUN_CALLBACK, reinterpret_cast(callback), reinterpret_cast(userdata)); } -} // namespace +} // namespace MainWindow diff --git a/Windows/MainWindow.h b/Windows/MainWindow.h index 9f0928ac6f..c4ebf26f0d 100644 --- a/Windows/MainWindow.h +++ b/Windows/MainWindow.h @@ -16,7 +16,7 @@ namespace MainWindow WM_USER_SAVESTATE_FINISH = WM_USER + 100, WM_USER_UPDATE_UI = WM_USER + 101, WM_USER_WINDOW_TITLE_CHANGED = WM_USER + 103, - WM_USER_TOGGLE_FULLSCREEN = WM_USER + 105, + WM_USER_APPLY_FULLSCREEN = WM_USER + 105, WM_USER_RESTART_EMUTHREAD = WM_USER + 106, WM_USER_SWITCHUMD_UPDATED = WM_USER + 107, WM_USER_RUN_CALLBACK = WM_USER + 108, @@ -74,7 +74,7 @@ namespace MainWindow HINSTANCE GetHInstance(); void ApplyFullscreenState(HWND hWnd, bool goingFullscreen); void Minimize(); - void SendToggleFullscreen(bool fullscreen); // To be used off-thread + void SendApplyFullscreenState(); // To be used off-thread void ToggleDebugConsoleVisibility(); void SetInternalResolution(int res = -1); void SetWindowSize(int zoom); diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 8cccf6223a..d8d89e6e86 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -882,7 +882,8 @@ namespace MainWindow { case ID_OPTIONS_FULLSCREEN: if (!g_Config.bShowImDebugger) { - SendToggleFullscreen(!g_Config.bFullScreen); + g_Config.bFullScreen = !g_Config.bFullScreen; + SendApplyFullscreenState(); } break; diff --git a/Windows/main.cpp b/Windows/main.cpp index 4b52ba4dd5..420784fe36 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -724,15 +724,9 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string }).detach(); return true; - case SystemRequestType::TOGGLE_FULLSCREEN_STATE: + case SystemRequestType::APPLY_FULLSCREEN_STATE: { - bool flag = !g_Config.bFullScreen; - if (param1 == "0") { - flag = false; - } else if (param1 == "1") { - flag = true; - } - MainWindow::SendToggleFullscreen(flag); + MainWindow::SendApplyFullscreenState(); return true; } case SystemRequestType::GRAPHICS_BACKEND_FAILED_ALERT: