Rework the internal API for applying the fullscreen state. Fixes.

This commit is contained in:
Henrik Rydgård
2026-02-02 11:45:46 +01:00
parent d331af58ab
commit ad4da764df
15 changed files with 85 additions and 102 deletions
+1 -1
View File
@@ -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";
+2 -3
View File
@@ -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) {
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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
+8 -18
View File
@@ -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<std::mutex> 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
}
*/
+3 -1
View File
@@ -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:
+8 -11
View File
@@ -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) {
+9 -11
View File
@@ -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;
-1
View File
@@ -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;
-2
View File
@@ -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;
+1 -1
View File
@@ -17,9 +17,9 @@
#pragma once
#include <list>
#include <memory>
#include <atomic>
#include <vector>
#include <thread>
#include "Common/CommonTypes.h"
+45 -40
View File
@@ -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<WINDOWPOS*>(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<WPARAM>(callback), reinterpret_cast<LPARAM>(userdata));
}
} // namespace
} // namespace MainWindow
+2 -2
View File
@@ -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);
+2 -1
View File
@@ -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;
+2 -8
View File
@@ -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: