diff --git a/Core/Config.cpp b/Core/Config.cpp index 347a91f8ba..e199af1b9f 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -513,6 +513,7 @@ static ConfigSetting graphicsSettings[] = { #ifndef MOBILE_DEVICE ConfigSetting("FullScreen", &g_Config.bFullScreen, false), + ConfigSetting("FullScreenMulti", &g_Config.bFullScreenMulti, false), #endif // TODO: Replace these settings with a list of options diff --git a/Core/Config.h b/Core/Config.h index 383629fd88..724ad8cb12 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -189,6 +189,7 @@ public: bool bTextureSecondaryCache; bool bVertexDecoderJit; bool bFullScreen; + bool bFullScreenMulti; int iInternalResolution; // 0 = Auto (native), 1 = 1x (480x272), 2 = 2x, 3 = 3x, 4 = 4x and so on. int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso int bHighQualityDepth; diff --git a/Core/Host.h b/Core/Host.h index 0b9b78f92e..0268a7587f 100644 --- a/Core/Host.h +++ b/Core/Host.h @@ -38,7 +38,6 @@ public: virtual void InitSound() = 0; virtual void UpdateSound() {} - virtual void GoFullscreen(bool) {} virtual void ShutdownSound() = 0; virtual void PollControllers() {} virtual void ToggleDebugConsoleVisibility() {} diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index d3ffcb3755..289dfda525 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -72,12 +72,13 @@ void CenterDisplayOutputRect(float *x, float *y, float *w, float *h, float origW return; } } else if (g_Config.iSmallDisplayZoomType == 2) { // Auto Scaling + // Stretch to 1080 for 272*4. But don't distort if not widescreen (i.e. ultrawide of halfwide.) float pixelCrop = frameH / 270.0f; float resCommonWidescreen = pixelCrop - floor(pixelCrop); - if (!rotated && resCommonWidescreen == 0.0f) { - *x = 0; + if (!rotated && resCommonWidescreen == 0.0f && frameW >= pixelCrop * 480.0f) { + *x = floorf((frameW - pixelCrop * 480.0f) * 0.5f); *y = floorf(-pixelCrop); - *w = floorf(frameW); + *w = floorf(pixelCrop * 480.0f); *h = floorf(pixelCrop * 272.0f); return; } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 03c8f8a21a..a3e09988da 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -263,6 +263,11 @@ void GameSettingsScreen::CreateViews() { #if !defined(MOBILE_DEVICE) graphicsSettings->Add(new CheckBox(&g_Config.bFullScreen, gr->T("FullScreen")))->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); + if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) { + CheckBox *fullscreenMulti = new CheckBox(&g_Config.bFullScreenMulti, gr->T("Use all displays")); + fullscreenMulti->SetEnabledPtr(&g_Config.bFullScreen); + graphicsSettings->Add(fullscreenMulti)->OnClick.Handle(this, &GameSettingsScreen::OnFullscreenChange); + } #endif // Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc. displayEditor_ = graphicsSettings->Add(new Choice(gr->T("Display layout editor"))); @@ -972,12 +977,7 @@ UI::EventReturn GameSettingsScreen::OnReloadCheats(UI::EventParams &e) { } UI::EventReturn GameSettingsScreen::OnFullscreenChange(UI::EventParams &e) { -#if defined(USING_WIN_UI) || defined(USING_QT_UI) - host->GoFullscreen(g_Config.bFullScreen); -#else - // SDL, basically. - System_SendMessage("toggle_fullscreen", ""); -#endif + System_SendMessage("toggle_fullscreen", g_Config.bFullScreen ? "1" : "0"); return UI::EVENT_DONE; } diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 7692a0ad38..ad3d46d8e8 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -91,7 +91,6 @@ struct VerySleepy_AddrInfo { wchar_t name[256]; }; -static RECT g_normalRC = {0}; static std::wstring windowTitle; extern ScreenManager *screenManager; @@ -117,6 +116,7 @@ namespace MainWindow static bool hideCursor = false; static int g_WindowState; static bool g_IgnoreWM_SIZE = false; + static bool inFullscreenResize = false; static bool inResizeMove = false; // gross hack @@ -172,7 +172,7 @@ namespace MainWindow } void SavePosition() { - if (g_Config.bFullScreen) + if (g_Config.bFullScreen || inFullscreenResize) return; WINDOWPLACEMENT placement; @@ -297,7 +297,11 @@ namespace MainWindow graphicsContext->Pause(); } + WINDOWPLACEMENT placement = { sizeof(WINDOWPLACEMENT) }; + GetWindowPlacement(hwndMain, &placement); + int oldWindowState = g_WindowState; + inFullscreenResize = true; g_IgnoreWM_SIZE = true; DWORD dwStyle; @@ -315,11 +319,9 @@ namespace MainWindow } 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) { + if (oldWindowState == SIZE_MAXIMIZED || placement.showCmd == SW_SHOWMAXIMIZED) { ShowWindow(hwndMain, SW_RESTORE); } - // Remember the normal window rectangle. - ::GetWindowRect(hWnd, &g_normalRC); // Remove caption and border styles. dwStyle = ::GetWindowLong(hWnd, GWL_STYLE); @@ -340,15 +342,31 @@ namespace MainWindow // Resize to the appropriate view. // If we're returning to window mode, re-apply the appropriate size setting. if (goingFullscreen) { - ShowWindow(hwndMain, SW_MAXIMIZE); + if (g_Config.bFullScreenMulti) { + // Maximize isn't enough to display on all monitors. + // Remember that negative coordinates may be valid. + int totalX = GetSystemMetrics(SM_XVIRTUALSCREEN); + int totalY = GetSystemMetrics(SM_YVIRTUALSCREEN); + int totalWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); + int totalHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); + MoveWindow(hwndMain, totalX, totalY, totalWidth, totalHeight, TRUE); + HandleSizeChange(oldWindowState); + } 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); } } + inFullscreenResize = false; CorrectCursor(); ShowOwnedPopups(hwndMain, goingFullscreen ? FALSE : TRUE); @@ -365,7 +383,6 @@ namespace MainWindow ShowWindow(hwndMain, SW_MINIMIZE); } - // Note that this also updates the config! Not very clean. RECT DetermineWindowRectangle() { const int virtualScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); const int virtualScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); @@ -407,25 +424,25 @@ namespace MainWindow int scale = (int)ceil(2.0 / dpi_scale); GetWindowSizeAtResolution(scale * (portrait ? 272 : 480), scale * (portrait ? 480 : 272), &windowWidth, &windowHeight); - g_Config.iWindowWidth = windowWidth; - g_Config.iWindowHeight = windowHeight; } // Then center if necessary. One dimension at a time. // Max is to make sure that if we end up making the window bigger than the screen (which is not ideal), the top left // corner, and thus the menu etc, will be visible. Also potential workaround for #9563. + int x = g_Config.iWindowX; + int y = g_Config.iWindowY; if (resetPositionX) { - g_Config.iWindowX = std::max(0, (currentScreenWidth - g_Config.iWindowWidth) / 2); + x = std::max(0, (currentScreenWidth - windowWidth) / 2); } if (resetPositionY) { - g_Config.iWindowY = std::max(0, (currentScreenHeight - g_Config.iWindowHeight) / 2); + y = std::max(0, (currentScreenHeight - windowHeight) / 2); } RECT rc; - rc.left = g_Config.iWindowX; - rc.right = rc.left + g_Config.iWindowWidth; - rc.top = g_Config.iWindowY; - rc.bottom = rc.top + g_Config.iWindowHeight; + rc.left = x; + rc.right = rc.left + windowWidth; + rc.top = y; + rc.bottom = rc.top + windowHeight; return rc; } @@ -441,6 +458,7 @@ namespace MainWindow BOOL Show(HINSTANCE hInstance) { hInst = hInstance; // Store instance handle in our global variable. RECT rc = DetermineWindowRectangle(); + SavePosition(); u32 style = WS_OVERLAPPEDWINDOW; diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index 30e110f678..e0eb554525 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -360,10 +360,6 @@ bool WindowsHost::CreateDesktopShortcut(std::string argumentPath, std::string ga return false; } -void WindowsHost::GoFullscreen(bool viewFullscreen) { - MainWindow::SendToggleFullscreen(viewFullscreen); -} - void WindowsHost::ToggleDebugConsoleVisibility() { MainWindow::ToggleDebugConsoleVisibility(); } diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index ae53d893f0..cb5cba2f1f 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -66,8 +66,6 @@ public: void NotifyUserMessage(const std::string &message, float duration = 1.0f, u32 color = 0x00FFFFFF, const char *id = nullptr) override; - void GoFullscreen(bool) override; - std::shared_ptr keyboard; GraphicsContext *GetGraphicsContext() { return gfx_; } diff --git a/Windows/main.cpp b/Windows/main.cpp index 37482f0737..f06d0c9880 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -212,6 +212,8 @@ int System_GetPropertyInt(SystemProperty prop) { return DEVICE_TYPE_DESKTOP; case SYSPROP_DISPLAY_DPI: return ScreenDPI(); + case SYSPROP_DISPLAY_COUNT: + return GetSystemMetrics(SM_CMONITORS); default: return -1; } @@ -263,6 +265,14 @@ void System_SendMessage(const char *command, const char *parameter) { MainWindow::BrowseAndBoot(""); } else if (!strcmp(command, "bgImage_browse")) { MainWindow::BrowseBackground(); + } else if (!strcmp(command, "toggle_fullscreen")) { + bool flag = !g_Config.bFullScreen; + if (strcmp(parameter, "0") == 0) { + flag = false; + } else if (strcmp(parameter, "1") == 0) { + flag = true; + } + MainWindow::SendToggleFullscreen(flag); } } diff --git a/ext/native/base/NativeApp.h b/ext/native/base/NativeApp.h index f253662d02..1f590a7d69 100644 --- a/ext/native/base/NativeApp.h +++ b/ext/native/base/NativeApp.h @@ -169,6 +169,7 @@ enum SystemProperty { SYSPROP_DISPLAY_YRES, SYSPROP_DISPLAY_REFRESH_RATE, // returns 1000*the refresh rate in Hz as it can be non-integer SYSPROP_DISPLAY_DPI, + SYSPROP_DISPLAY_COUNT, SYSPROP_MOGA_VERSION, SYSPROP_DEVICE_TYPE, diff --git a/ext/native/base/PCMain.cpp b/ext/native/base/PCMain.cpp index f4081e88a6..256121384e 100644 --- a/ext/native/base/PCMain.cpp +++ b/ext/native/base/PCMain.cpp @@ -66,6 +66,7 @@ GlobalUIState GetUIState(); static SDL_Window* g_Screen = NULL; static bool g_ToggleFullScreenNextFrame = false; +static int g_ToggleFullScreenType; static int g_QuitRequested = 0; static int g_DesktopWidth = 0; @@ -248,6 +249,14 @@ void Vibrate(int length_ms) { void System_SendMessage(const char *command, const char *parameter) { if (!strcmp(command, "toggle_fullscreen")) { g_ToggleFullScreenNextFrame = true; + if (strcmp(parameter, "1") == 0) { + g_ToggleFullScreenType = 1; + } else if (strcmp(parameter, "0") == 0) { + g_ToggleFullScreenType = 0; + } else { + // Just toggle. + g_ToggleFullScreenType = -1; + } } else if (!strcmp(command, "finish")) { // Do a clean exit g_QuitRequested = true; @@ -391,7 +400,14 @@ void ToggleFullScreenIfFlagSet() { g_ToggleFullScreenNextFrame = false; Uint32 window_flags = SDL_GetWindowFlags(g_Screen); - SDL_SetWindowFullscreen(g_Screen, window_flags ^ SDL_WINDOW_FULLSCREEN_DESKTOP); + if (g_ToggleFullScreenType == -1) { + window_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP; + } else if (g_ToggleFullScreenType == 1) { + window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + } else { + window_flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP; + } + SDL_SetWindowFullscreen(g_Screen, window_flags); } }