mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-22 02:39:05 +02:00
Rework fullscreen on Windows based on tests
Test implementation in https://github.com/hrydgard/fullscreen-test
This commit is contained in:
1 parent
7c2632cd55
commit
d331af58ab
2 files changed
+128
-89
No files matched your search
+127
-88
@@ -150,8 +150,6 @@ namespace MainWindow {
|
||||
|
||||
static bool mouseButtonDown = false;
|
||||
static bool hideCursor = false;
|
||||
static int g_WindowState;
|
||||
static bool g_IgnoreWM_SIZE = false;
|
||||
static bool inFullscreenResize = false;
|
||||
static bool inResizeMove = false;
|
||||
static bool hasFocus = true;
|
||||
@@ -159,7 +157,7 @@ namespace MainWindow {
|
||||
|
||||
static bool disasmMapLoadPending = false;
|
||||
static bool memoryMapLoadPending = false;
|
||||
static bool wasMinimized = false;
|
||||
static bool g_wasMinimized = false;
|
||||
|
||||
// gross hack
|
||||
bool noFocusPause = false; // TOGGLE_PAUSE state to override pause on lost focus
|
||||
@@ -193,12 +191,14 @@ namespace MainWindow {
|
||||
}
|
||||
|
||||
void SavePosition() {
|
||||
if (g_Config.bFullScreen || inFullscreenResize)
|
||||
return;
|
||||
|
||||
WINDOWPLACEMENT placement{};
|
||||
GetWindowPlacement(hwndMain, &placement);
|
||||
g_Config.iWindowSizeState = (int)ShowCmdToWindowSizeState(placement.showCmd);
|
||||
WindowSizeState sizeState = ShowCmdToWindowSizeState(placement.showCmd);
|
||||
if (sizeState == WindowSizeState::Minimized) {
|
||||
// Don't save minimized position.
|
||||
sizeState = WindowSizeState::Normal;
|
||||
}
|
||||
g_Config.iWindowSizeState = (int)sizeState;
|
||||
g_Config.iWindowX = placement.rcNormalPosition.left;
|
||||
g_Config.iWindowY = placement.rcNormalPosition.top;
|
||||
g_Config.iWindowWidth = placement.rcNormalPosition.right - placement.rcNormalPosition.left;
|
||||
@@ -216,6 +216,10 @@ namespace MainWindow {
|
||||
|
||||
void SetWindowSize(int zoom) {
|
||||
AssertCurrentThreadName("Main");
|
||||
|
||||
if (g_Config.bFullScreen || inFullscreenResize)
|
||||
return;
|
||||
|
||||
// Actually, auto mode should be more granular...
|
||||
int width, height;
|
||||
const DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
||||
@@ -241,7 +245,7 @@ namespace MainWindow {
|
||||
}
|
||||
|
||||
void CorrectCursor() {
|
||||
bool autoHide = ((g_Config.bFullScreen && !mouseButtonDown) || (g_Config.bMouseControl && trapMouse)) && GetUIState() == UISTATE_INGAME;
|
||||
const bool autoHide = ((g_Config.bFullScreen && !mouseButtonDown) || (g_Config.bMouseControl && trapMouse)) && GetUIState() == UISTATE_INGAME;
|
||||
if (autoHide && (hideCursor || g_Config.bMouseControl)) {
|
||||
while (cursorCounter >= 0) {
|
||||
cursorCounter = ShowCursor(FALSE);
|
||||
@@ -264,7 +268,6 @@ namespace MainWindow {
|
||||
}
|
||||
|
||||
static void HandleSizeChange(int newSizingType) {
|
||||
SavePosition();
|
||||
Native_NotifyWindowHidden(false);
|
||||
if (!g_Config.bPauseWhenMinimized) {
|
||||
System_PostUIMessage(UIMessage::WINDOW_MINIMIZED, "false");
|
||||
@@ -287,91 +290,82 @@ namespace MainWindow {
|
||||
System_PostUIMessage(UIMessage::GPU_DISPLAY_RESIZED);
|
||||
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
|
||||
}
|
||||
|
||||
// Don't save the window state if fullscreen.
|
||||
if (!g_Config.bFullScreen) {
|
||||
g_WindowState = newSizingType;
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleFullscreen(HWND hWnd, bool goingFullscreen) {
|
||||
void ApplyFullscreenState(HWND hWnd, bool goFullscreen) {
|
||||
GraphicsContext *graphicsContext = PSP_CoreParameter().graphicsContext;
|
||||
// Make sure no rendering is happening during the switch.
|
||||
if (graphicsContext) {
|
||||
graphicsContext->Pause();
|
||||
}
|
||||
|
||||
WINDOWPLACEMENT placement = { sizeof(WINDOWPLACEMENT) };
|
||||
GetWindowPlacement(hwndMain, &placement);
|
||||
const DWORD prevStyle = GetWindowLong(hWnd, GWL_STYLE);
|
||||
const bool isCurrentlyFullscreen = !(prevStyle & WS_OVERLAPPEDWINDOW);
|
||||
|
||||
const int oldWindowState = g_WindowState;
|
||||
inFullscreenResize = true;
|
||||
g_IgnoreWM_SIZE = true;
|
||||
|
||||
DWORD dwStyle;
|
||||
|
||||
if (!goingFullscreen) {
|
||||
dwStyle = ::GetWindowLong(hWnd, GWL_STYLE);
|
||||
|
||||
// Remove popup
|
||||
dwStyle &= ~WS_POPUP;
|
||||
// Re-add caption and border styles.
|
||||
dwStyle |= WS_OVERLAPPEDWINDOW;
|
||||
} else {
|
||||
// If the window was maximized before going fullscreen, make sure to restore first
|
||||
// in order not to have the taskbar show up on top of PPSSPP.
|
||||
if (oldWindowState == SIZE_MAXIMIZED || placement.showCmd == SW_SHOWMAXIMIZED) {
|
||||
ShowWindow(hwndMain, SW_RESTORE);
|
||||
if (goFullscreen && !isCurrentlyFullscreen) {
|
||||
// Transitioning to Fullscreen
|
||||
WINDOWPLACEMENT wp = {sizeof(WINDOWPLACEMENT)};
|
||||
if (GetWindowPlacement(hWnd, &wp)) {
|
||||
g_Config.iWindowX = wp.rcNormalPosition.left;
|
||||
g_Config.iWindowY = wp.rcNormalPosition.top;
|
||||
g_Config.iWindowWidth = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
|
||||
g_Config.iWindowHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
|
||||
wp.showCmd = SW_SHOW;
|
||||
}
|
||||
|
||||
// Remove caption and border styles.
|
||||
dwStyle = ::GetWindowLong(hWnd, GWL_STYLE);
|
||||
dwStyle &= ~WS_OVERLAPPEDWINDOW;
|
||||
// Add Popup
|
||||
dwStyle |= WS_POPUP;
|
||||
}
|
||||
|
||||
::SetWindowLong(hWnd, GWL_STYLE, dwStyle);
|
||||
|
||||
// Remove the menu bar if going fullscreen. This can trigger WM_SIZE because the contents change size.
|
||||
::SetMenu(hWnd, goingFullscreen || !g_Config.bShowMenuBar ? NULL : g_hMenu);
|
||||
|
||||
g_Config.bFullScreen = goingFullscreen;
|
||||
|
||||
g_IgnoreWM_SIZE = false;
|
||||
|
||||
// Resize to the appropriate view.
|
||||
// If we're returning to window mode, re-apply the appropriate size setting.
|
||||
if (goingFullscreen) {
|
||||
if (g_Config.bFullScreenMulti) {
|
||||
SetMenu(hWnd, NULL);
|
||||
// Strip all decorations
|
||||
SetWindowLong(hWnd, GWL_STYLE, prevStyle & ~WS_OVERLAPPEDWINDOW);
|
||||
// Maximize isn't enough to display on all monitors.
|
||||
// Remember that negative coordinates may be valid.
|
||||
const int totalX = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||||
const int totalY = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
||||
const int totalWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
const int totalHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
MoveWindow(hwndMain, totalX, totalY, totalWidth, totalHeight, TRUE);
|
||||
HandleSizeChange(oldWindowState);
|
||||
ShowWindow(hwndMain, SW_SHOW);
|
||||
SetWindowPos(hWnd, HWND_TOP,
|
||||
totalX, totalY,
|
||||
totalWidth, totalHeight,
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
g_Config.bFullScreen = true;
|
||||
} else {
|
||||
ShowWindow(hwndMain, SW_MAXIMIZE);
|
||||
}
|
||||
} else {
|
||||
ShowWindow(hwndMain, oldWindowState == SIZE_MAXIMIZED ? SW_MAXIMIZE : SW_RESTORE);
|
||||
if (g_Config.bFullScreenMulti && oldWindowState != SIZE_MAXIMIZED) {
|
||||
// Return the screen to where it was.
|
||||
MoveWindow(hwndMain, g_Config.iWindowX, g_Config.iWindowY, g_Config.iWindowWidth, g_Config.iWindowHeight, TRUE);
|
||||
}
|
||||
if (oldWindowState == SIZE_MAXIMIZED) {
|
||||
// WM_SIZE wasn't sent, since the size didn't change (it was full screen before and after.)
|
||||
HandleSizeChange(oldWindowState);
|
||||
MONITORINFO mi = {sizeof(mi)};
|
||||
if (GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &mi)) {
|
||||
SetMenu(hWnd, NULL);
|
||||
// Strip all decorations
|
||||
SetWindowLong(hWnd, GWL_STYLE, prevStyle & ~WS_OVERLAPPEDWINDOW);
|
||||
|
||||
SetWindowPos(hWnd, HWND_TOP,
|
||||
mi.rcMonitor.left, mi.rcMonitor.top,
|
||||
mi.rcMonitor.right - mi.rcMonitor.left,
|
||||
mi.rcMonitor.bottom - mi.rcMonitor.top,
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
|
||||
g_Config.bFullScreen = true;
|
||||
}
|
||||
}
|
||||
} else if (!goFullscreen && isCurrentlyFullscreen) {
|
||||
// Transitioning to Windowed
|
||||
SetWindowLong(hWnd, GWL_STYLE, prevStyle | WS_OVERLAPPEDWINDOW);
|
||||
SetMenu(hWnd, g_hMenu);
|
||||
|
||||
WINDOWPLACEMENT wp = {sizeof(WINDOWPLACEMENT)};
|
||||
wp.showCmd = WindowSizeStateToShowCmd((WindowSizeState)g_Config.iWindowSizeState);
|
||||
wp.rcNormalPosition = {g_Config.iWindowX, g_Config.iWindowY, g_Config.iWindowX + g_Config.iWindowWidth, g_Config.iWindowY + g_Config.iWindowHeight};
|
||||
|
||||
if (wp.showCmd == SW_SHOWMINIMIZED) wp.showCmd = SW_SHOWNORMAL;
|
||||
|
||||
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;
|
||||
CorrectCursor();
|
||||
|
||||
ShowOwnedPopups(hwndMain, goingFullscreen ? FALSE : TRUE);
|
||||
ShowOwnedPopups(hwndMain, goFullscreen ? FALSE : TRUE);
|
||||
W32Util::MakeTopMost(hwndMain, g_Config.bTopMost);
|
||||
|
||||
WindowsRawInput::NotifyMenu();
|
||||
@@ -386,7 +380,8 @@ namespace MainWindow {
|
||||
g_InputManager.LoseFocus();
|
||||
}
|
||||
|
||||
RECT DetermineWindowRectangle() {
|
||||
// TODO: Currently unused.
|
||||
RECT DetermineDefaultWindowRectangle() {
|
||||
const int virtualScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
const int virtualScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
const int virtualScreenX = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||||
@@ -502,7 +497,7 @@ namespace MainWindow {
|
||||
hideCursor = true;
|
||||
SetTimer(hwndMain, TIMER_CURSORUPDATE, CURSORUPDATE_INTERVAL_MS, 0);
|
||||
|
||||
ToggleFullscreen(hwndMain, g_Config.bFullScreen);
|
||||
ApplyFullscreenState(hwndMain, g_Config.bFullScreen);
|
||||
|
||||
W32Util::MakeTopMost(hwndMain, g_Config.bTopMost);
|
||||
|
||||
@@ -804,10 +799,61 @@ namespace MainWindow {
|
||||
// Then never erase, let the OpenGL drawing take care of everything.
|
||||
return 1;
|
||||
|
||||
case WM_MOVE:
|
||||
SavePosition();
|
||||
case WM_USER_TOGGLE_FULLSCREEN:
|
||||
ApplyFullscreenState(hwndMain, wParam ? true : false);
|
||||
break;
|
||||
|
||||
case WM_DISPLAYCHANGE:
|
||||
// If resolution changes while we are fullscreen, re-snap to the new monitor size
|
||||
if (g_Config.bFullScreen) {
|
||||
MONITORINFO mi = {sizeof(mi)};
|
||||
if (GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &mi)) {
|
||||
SetWindowPos(hWnd, HWND_TOP,
|
||||
mi.rcMonitor.left, mi.rcMonitor.top,
|
||||
mi.rcMonitor.right - mi.rcMonitor.left,
|
||||
mi.rcMonitor.bottom - mi.rcMonitor.top,
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
const WINDOWPOS *pos = reinterpret_cast<WINDOWPOS*>(lParam);
|
||||
if (!pos) {
|
||||
// Uh?
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
const bool sizeChanged = !(pos->flags & SWP_NOSIZE);
|
||||
if (sizeChanged) {
|
||||
if (g_Config.bFullScreen) {
|
||||
MONITORINFO mi = {sizeof(mi)};
|
||||
if (GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &mi)) {
|
||||
int monWidth = mi.rcMonitor.right - mi.rcMonitor.left;
|
||||
int monHeight = mi.rcMonitor.bottom - mi.rcMonitor.top;
|
||||
|
||||
// If the new size is no longer the full monitor size, drop FS state (put back the menu
|
||||
// and recalculate window decorations without actually changing the size of the window).
|
||||
if (pos->cx != monWidth || pos->cy != monHeight) {
|
||||
g_Config.bFullScreen = false;
|
||||
if (GetMenu(hWnd) == NULL) {
|
||||
SetMenu(hWnd, g_hMenu);
|
||||
}
|
||||
DWORD style = GetWindowLong(hWnd, GWL_STYLE);
|
||||
if (!(style & WS_CAPTION)) {
|
||||
SetWindowLong(hWnd, GWL_STYLE, style | WS_OVERLAPPEDWINDOW);
|
||||
SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// This means that WM_SIZE and WM_MOVE won't be sent.
|
||||
HandleSizeChange(SIZE_RESTORED);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_ENTERSIZEMOVE:
|
||||
inResizeMove = true;
|
||||
break;
|
||||
@@ -821,17 +867,12 @@ namespace MainWindow {
|
||||
switch (wParam) {
|
||||
case SIZE_RESTORED:
|
||||
case SIZE_MAXIMIZED:
|
||||
if (g_IgnoreWM_SIZE) {
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
} else if (!inResizeMove) {
|
||||
if (!inResizeMove) {
|
||||
HandleSizeChange(wParam);
|
||||
}
|
||||
if (hasFocus) {
|
||||
g_InputManager.GainFocus();
|
||||
}
|
||||
if (wasMinimized) {
|
||||
if (g_wasMinimized) {
|
||||
System_PostUIMessage(UIMessage::WINDOW_RESTORED, "true");
|
||||
wasMinimized = false;
|
||||
g_wasMinimized = false;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -840,13 +881,11 @@ namespace MainWindow {
|
||||
if (!g_Config.bPauseWhenMinimized) {
|
||||
System_PostUIMessage(UIMessage::WINDOW_MINIMIZED, "true");
|
||||
}
|
||||
g_InputManager.LoseFocus();
|
||||
wasMinimized = true;
|
||||
g_wasMinimized = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SavePosition();
|
||||
break;
|
||||
|
||||
// Wheel events have to stay in WndProc for compatibility with older Windows(7). See #12156
|
||||
@@ -879,6 +918,9 @@ namespace MainWindow {
|
||||
hideCursor = true;
|
||||
KillTimer(hWnd, TIMER_CURSORMOVEUPDATE);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -891,10 +933,6 @@ namespace MainWindow {
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_USER_TOGGLE_FULLSCREEN:
|
||||
ToggleFullscreen(hwndMain, wParam ? true : false);
|
||||
break;
|
||||
|
||||
case WM_INPUT:
|
||||
return WindowsRawInput::Process(hWnd, wParam, lParam);
|
||||
|
||||
@@ -972,6 +1010,7 @@ namespace MainWindow {
|
||||
}
|
||||
|
||||
case WM_DESTROY:
|
||||
SavePosition();
|
||||
g_InputManager.StopPolling();
|
||||
g_InputManager.Shutdown();
|
||||
WindowsRawInput::Shutdown();
|
||||
|
||||
Reference in new issue
Block a user