From 2c9f1efc0b03f864f2d04306a98092ad3949aa7a Mon Sep 17 00:00:00 2001 From: kaetemi Date: Thu, 7 Aug 2014 04:18:17 +0200 Subject: [PATCH] GL: Handle borderless fullscreen to specified monitor internally --- .../src/3d/driver/opengl/driver_opengl.cpp | 4 + code/nel/src/3d/driver/opengl/driver_opengl.h | 6 + .../3d/driver/opengl/driver_opengl_window.cpp | 110 ++++++++++++++---- code/nel/src/3d/stereo_ovr_04.cpp | 4 +- 4 files changed, 100 insertions(+), 24 deletions(-) diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.cpp b/code/nel/src/3d/driver/opengl/driver_opengl.cpp index ce60d7f42..e9965e0f1 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl.cpp @@ -234,6 +234,10 @@ CDriverGL::CDriverGL() _CursorScale = 1.f; _MouseCaptured = false; +#if defined(NL_OS_WINDOWS) + _BorderlessFullscreen = false; +#endif + _NeedToRestaureGammaRamp = false; _win = EmptyWindow; diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.h b/code/nel/src/3d/driver/opengl/driver_opengl.h index c4540b9da..fb6069447 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.h +++ b/code/nel/src/3d/driver/opengl/driver_opengl.h @@ -996,6 +996,12 @@ private: EWindowStyle getWindowStyle() const; bool setWindowStyle(EWindowStyle windowStyle); +#if defined(NL_OS_WINDOWS) + static BOOL CALLBACK monitorEnumProcFullscreen(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData); + bool _BorderlessFullscreen; +#endif + std::string _CurrentDisplayDevice; + // Methods to manage screen resolutions bool restoreScreenMode(); bool saveScreenMode(); diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp index cb93a900c..2e9da2431 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp @@ -1276,11 +1276,12 @@ static sint modeInfoToFrequency(XF86VidModeModeInfo *info) struct CMonitorEnumParams { public: - HWND Window; - const char *deviceName; + CDriverGL *Driver; + const char *DeviceName; + bool Success; }; -static BOOL CALLBACK monitorEnumProcFullscreen(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData) +BOOL CALLBACK CDriverGL::monitorEnumProcFullscreen(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData) { CMonitorEnumParams *p = reinterpret_cast(dwData); @@ -1291,29 +1292,36 @@ static BOOL CALLBACK monitorEnumProcFullscreen(HMONITOR hMonitor, HDC, LPRECT, L nldebug("3D: Monitor: '%s'", monitorInfo.szDevice); size_t devLen = strlen(monitorInfo.szDevice); - size_t targetLen = strlen(p->deviceName); + size_t targetLen = strlen(p->DeviceName); nlassert(devLen < 32); size_t minLen = min(devLen, targetLen); - if (!memcmp(monitorInfo.szDevice, p->deviceName, minLen)) + if (!memcmp(monitorInfo.szDevice, p->DeviceName, minLen)) { if (devLen == targetLen - || (devLen < targetLen && (p->deviceName[minLen] == '\\')) + || (devLen < targetLen && (p->DeviceName[minLen] == '\\')) || (devLen > targetLen && (monitorInfo.szDevice[minLen] == '\\'))) { - nldebug("3D: Remap '%s' to '%s'", p->deviceName, monitorInfo.szDevice); - nldebug("Found our monitor at %i, %i", monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top); - LONG dwStyle = GetWindowLong(p->Window, GWL_STYLE); - SetWindowLong(p->Window, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW); - SetWindowPos(p->Window, NULL, + nldebug("3D: Remapping '%s' to '%s'", p->DeviceName, monitorInfo.szDevice); + nldebug("3D: Found requested monitor at %i, %i", monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top); + LONG dwStyle = GetWindowLong(p->Driver->_win, GWL_STYLE); + SetWindowLong(p->Driver->_win, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW); + SetWindowPos(p->Driver->_win, NULL, monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, SWP_FRAMECHANGED); + p->Driver->_WindowX = monitorInfo.rcMonitor.left; + p->Driver->_WindowY = monitorInfo.rcMonitor.top; + p->Driver->_CurrentDisplayDevice = std::string(p->DeviceName); + p->Driver->_BorderlessFullscreen = true; + p->Driver->_CurrentMode.Windowed = false; + p->Success = true; return FALSE; } } + p->Success = false; return TRUE; // continue }; @@ -1327,6 +1335,19 @@ bool CDriverGL::setScreenMode(const GfxMode &mode) nldebug("3D: setScreenMode"); +#if defined(NL_OS_WINDOWS) + if (_BorderlessFullscreen) + { + _BorderlessFullscreen = false; + LONG dwStyle = GetWindowLong(_win, GWL_STYLE); + dwStyle |= WS_OVERLAPPEDWINDOW; + if (!_Resizable) dwStyle ^= WS_MAXIMIZEBOX|WS_THICKFRAME; + SetWindowLong(_win, GWL_STYLE, dwStyle); + SetWindowPos(_win, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + _CurrentMode.Windowed = true; + } +#endif + if (mode.Windowed) { // if fullscreen, switch back to desktop screen mode @@ -1336,7 +1357,7 @@ bool CDriverGL::setScreenMode(const GfxMode &mode) return true; } - if (!mode.DisplayDevice.empty()) + if (_CurrentDisplayDevice != mode.DisplayDevice) restoreScreenMode(); // save previous screen mode only if switching from windowed to fullscreen @@ -1345,7 +1366,8 @@ bool CDriverGL::setScreenMode(const GfxMode &mode) // if switching exactly to the same screen mode, doesn't change it GfxMode previousMode; - if (mode.DisplayDevice.empty() && getCurrentScreenMode(previousMode) + if (_CurrentDisplayDevice == mode.DisplayDevice + && getCurrentScreenMode(previousMode) && mode.Width == previousMode.Width && mode.Height == previousMode.Height && mode.Depth == previousMode.Depth @@ -1386,10 +1408,10 @@ bool CDriverGL::setScreenMode(const GfxMode &mode) nlwarning("3D: Fullscreen mode switch failed (%i)", (sint)resex); // Workaround, resize to monitor and make borderless CMonitorEnumParams p; - p.deviceName = deviceName; - p.Window = _win; + p.DeviceName = deviceName; + p.Driver = this; EnumDisplayMonitors(NULL, NULL, monitorEnumProcFullscreen, (LPARAM)&p); - return false; // FIXME: This is a hack, don't process further + return p.Success; } } else @@ -1805,7 +1827,11 @@ bool CDriverGL::setWindowStyle(EWindowStyle windowStyle) dwNewStyle |= WS_VISIBLE; if (dwStyle != dwNewStyle) + { SetWindowLong(_win, GWL_STYLE, dwNewStyle); + if (windowStyle == EWSWindowed) + SetWindowPos(_win, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); + } // if (windowStyle == EWSMaximized && isVisible && !isMaximized) // ShowWindow(_hWnd, SW_SHOWMAXIMIZED); @@ -1925,17 +1951,32 @@ bool CDriverGL::setMode(const GfxMode& mode) if (!_DestroyWindow) return true; +#if defined(NL_OS_WINDOWS) + // save relative cursor + POINT cursorPos; + BOOL cursorPosOk = isSystemCursorInClientArea() + && GetCursorPos(&cursorPos) + && ScreenToClient(_win, &cursorPos); + sint curX = (sint)cursorPos.x * (sint)mode.Width; + sint curY = (sint)cursorPos.y * (sint)mode.Height; + if (_BorderlessFullscreen) + ReleaseCapture(); +#endif + if (!setScreenMode(mode)) return false; - // when changing window style, it's possible system change window size too - setWindowStyle(mode.Windowed ? EWSWindowed : EWSFullscreen); + if (!_BorderlessFullscreen) + { + // when changing window style, it's possible system change window size too + setWindowStyle(mode.Windowed ? EWSWindowed : EWSFullscreen); - if (!mode.Windowed) - _CurrentMode.Depth = mode.Depth; + if (!mode.Windowed) + _CurrentMode.Depth = mode.Depth; - setWindowSize(mode.Width, mode.Height); - setWindowPos(_WindowX, _WindowY); + setWindowSize(mode.Width, mode.Height); + setWindowPos(_WindowX, _WindowY); + } switch (_CurrentMode.Depth) { @@ -1944,6 +1985,19 @@ bool CDriverGL::setMode(const GfxMode& mode) case 32: _ColorDepth = ColorDepth32; break; } +#if defined(NL_OS_WINDOWS) + // restore relative cursor + if (cursorPosOk) + { + cursorPos.x = curX / (sint)mode.Width; + cursorPos.y = curY / (sint)mode.Height; + ClientToScreen(_win, &cursorPos); + SetCursorPos(cursorPos.x, cursorPos.y); + if (_BorderlessFullscreen) + SetCapture(_win); + } +#endif + // set color depth for custom cursor updateCursor(true); @@ -2359,8 +2413,20 @@ void CDriverGL::setWindowPos(sint32 x, sint32 y) #ifdef NL_OS_WINDOWS + // save relative cursor + POINT cursorPos; + BOOL cursorPosOk = isSystemCursorInClientArea() + && GetCursorPos(&cursorPos) + && ScreenToClient(_win, &cursorPos); + SetWindowPos(_win, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); + if (cursorPosOk) + { + ClientToScreen(_win, &cursorPos); + SetCursorPos(cursorPos.x, cursorPos.y); + } + #elif defined(NL_OS_MAC) // get the rect (position, size) of the screen with menu bar NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame]; diff --git a/code/nel/src/3d/stereo_ovr_04.cpp b/code/nel/src/3d/stereo_ovr_04.cpp index 0fd4b9ba2..3eb666360 100644 --- a/code/nel/src/3d/stereo_ovr_04.cpp +++ b/code/nel/src/3d/stereo_ovr_04.cpp @@ -465,12 +465,12 @@ void CStereoOVR::attachToDisplay() void CStereoOVR::detachFromDisplay() { - if (!m_OriginalMode.Windowed) + /*if (!m_OriginalMode.Windowed) { m_OriginalMode.Windowed = true; m_Driver->setMode(m_OriginalMode); m_OriginalMode.Windowed = false; - } + }*/ m_Driver->setMode(m_OriginalMode); m_Driver->setWindowPos(m_OriginalWinPosX, m_OriginalWinPosY); m_AttachedDisplay = false;