GL: Handle borderless fullscreen to specified monitor internally

This commit is contained in:
kaetemi 2014-08-07 04:18:17 +02:00
parent 7bd9216a6f
commit c2d39e8bdf
4 changed files with 100 additions and 24 deletions

View file

@ -234,6 +234,10 @@ CDriverGL::CDriverGL()
_CursorScale = 1.f; _CursorScale = 1.f;
_MouseCaptured = false; _MouseCaptured = false;
#if defined(NL_OS_WINDOWS)
_BorderlessFullscreen = false;
#endif
_NeedToRestaureGammaRamp = false; _NeedToRestaureGammaRamp = false;
_win = EmptyWindow; _win = EmptyWindow;

View file

@ -996,6 +996,12 @@ private:
EWindowStyle getWindowStyle() const; EWindowStyle getWindowStyle() const;
bool setWindowStyle(EWindowStyle windowStyle); 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 // Methods to manage screen resolutions
bool restoreScreenMode(); bool restoreScreenMode();
bool saveScreenMode(); bool saveScreenMode();

View file

@ -1276,11 +1276,12 @@ static sint modeInfoToFrequency(XF86VidModeModeInfo *info)
struct CMonitorEnumParams struct CMonitorEnumParams
{ {
public: public:
HWND Window; CDriverGL *Driver;
const char *deviceName; 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<CMonitorEnumParams *>(dwData); CMonitorEnumParams *p = reinterpret_cast<CMonitorEnumParams *>(dwData);
@ -1291,29 +1292,36 @@ static BOOL CALLBACK monitorEnumProcFullscreen(HMONITOR hMonitor, HDC, LPRECT, L
nldebug("3D: Monitor: '%s'", monitorInfo.szDevice); nldebug("3D: Monitor: '%s'", monitorInfo.szDevice);
size_t devLen = strlen(monitorInfo.szDevice); size_t devLen = strlen(monitorInfo.szDevice);
size_t targetLen = strlen(p->deviceName); size_t targetLen = strlen(p->DeviceName);
nlassert(devLen < 32); nlassert(devLen < 32);
size_t minLen = min(devLen, targetLen); size_t minLen = min(devLen, targetLen);
if (!memcmp(monitorInfo.szDevice, p->deviceName, minLen)) if (!memcmp(monitorInfo.szDevice, p->DeviceName, minLen))
{ {
if (devLen == targetLen if (devLen == targetLen
|| (devLen < targetLen && (p->deviceName[minLen] == '\\')) || (devLen < targetLen && (p->DeviceName[minLen] == '\\'))
|| (devLen > targetLen && (monitorInfo.szDevice[minLen] == '\\'))) || (devLen > targetLen && (monitorInfo.szDevice[minLen] == '\\')))
{ {
nldebug("3D: Remap '%s' to '%s'", p->deviceName, monitorInfo.szDevice); nldebug("3D: Remapping '%s' to '%s'", p->DeviceName, monitorInfo.szDevice);
nldebug("Found our monitor at %i, %i", monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top); nldebug("3D: Found requested monitor at %i, %i", monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top);
LONG dwStyle = GetWindowLong(p->Window, GWL_STYLE); LONG dwStyle = GetWindowLong(p->Driver->_win, GWL_STYLE);
SetWindowLong(p->Window, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW); SetWindowLong(p->Driver->_win, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW);
SetWindowPos(p->Window, NULL, SetWindowPos(p->Driver->_win, NULL,
monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.left,
monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.top,
monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top,
SWP_FRAMECHANGED); 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; return FALSE;
} }
} }
p->Success = false;
return TRUE; // continue return TRUE; // continue
}; };
@ -1327,6 +1335,19 @@ bool CDriverGL::setScreenMode(const GfxMode &mode)
nldebug("3D: setScreenMode"); 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 (mode.Windowed)
{ {
// if fullscreen, switch back to desktop screen mode // if fullscreen, switch back to desktop screen mode
@ -1336,7 +1357,7 @@ bool CDriverGL::setScreenMode(const GfxMode &mode)
return true; return true;
} }
if (!mode.DisplayDevice.empty()) if (_CurrentDisplayDevice != mode.DisplayDevice)
restoreScreenMode(); restoreScreenMode();
// save previous screen mode only if switching from windowed to fullscreen // 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 // if switching exactly to the same screen mode, doesn't change it
GfxMode previousMode; GfxMode previousMode;
if (mode.DisplayDevice.empty() && getCurrentScreenMode(previousMode) if (_CurrentDisplayDevice == mode.DisplayDevice
&& getCurrentScreenMode(previousMode)
&& mode.Width == previousMode.Width && mode.Width == previousMode.Width
&& mode.Height == previousMode.Height && mode.Height == previousMode.Height
&& mode.Depth == previousMode.Depth && mode.Depth == previousMode.Depth
@ -1386,10 +1408,10 @@ bool CDriverGL::setScreenMode(const GfxMode &mode)
nlwarning("3D: Fullscreen mode switch failed (%i)", (sint)resex); nlwarning("3D: Fullscreen mode switch failed (%i)", (sint)resex);
// Workaround, resize to monitor and make borderless // Workaround, resize to monitor and make borderless
CMonitorEnumParams p; CMonitorEnumParams p;
p.deviceName = deviceName; p.DeviceName = deviceName;
p.Window = _win; p.Driver = this;
EnumDisplayMonitors(NULL, NULL, monitorEnumProcFullscreen, (LPARAM)&p); EnumDisplayMonitors(NULL, NULL, monitorEnumProcFullscreen, (LPARAM)&p);
return false; // FIXME: This is a hack, don't process further return p.Success;
} }
} }
else else
@ -1805,7 +1827,11 @@ bool CDriverGL::setWindowStyle(EWindowStyle windowStyle)
dwNewStyle |= WS_VISIBLE; dwNewStyle |= WS_VISIBLE;
if (dwStyle != dwNewStyle) if (dwStyle != dwNewStyle)
{
SetWindowLong(_win, GWL_STYLE, 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) // if (windowStyle == EWSMaximized && isVisible && !isMaximized)
// ShowWindow(_hWnd, SW_SHOWMAXIMIZED); // ShowWindow(_hWnd, SW_SHOWMAXIMIZED);
@ -1925,17 +1951,32 @@ bool CDriverGL::setMode(const GfxMode& mode)
if (!_DestroyWindow) if (!_DestroyWindow)
return true; 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)) if (!setScreenMode(mode))
return false; return false;
// when changing window style, it's possible system change window size too if (!_BorderlessFullscreen)
setWindowStyle(mode.Windowed ? EWSWindowed : EWSFullscreen); {
// when changing window style, it's possible system change window size too
setWindowStyle(mode.Windowed ? EWSWindowed : EWSFullscreen);
if (!mode.Windowed) if (!mode.Windowed)
_CurrentMode.Depth = mode.Depth; _CurrentMode.Depth = mode.Depth;
setWindowSize(mode.Width, mode.Height); setWindowSize(mode.Width, mode.Height);
setWindowPos(_WindowX, _WindowY); setWindowPos(_WindowX, _WindowY);
}
switch (_CurrentMode.Depth) switch (_CurrentMode.Depth)
{ {
@ -1944,6 +1985,19 @@ bool CDriverGL::setMode(const GfxMode& mode)
case 32: _ColorDepth = ColorDepth32; break; 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 // set color depth for custom cursor
updateCursor(true); updateCursor(true);
@ -2359,8 +2413,20 @@ void CDriverGL::setWindowPos(sint32 x, sint32 y)
#ifdef NL_OS_WINDOWS #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); 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) #elif defined(NL_OS_MAC)
// get the rect (position, size) of the screen with menu bar // get the rect (position, size) of the screen with menu bar
NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame]; NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame];

View file

@ -465,12 +465,12 @@ void CStereoOVR::attachToDisplay()
void CStereoOVR::detachFromDisplay() void CStereoOVR::detachFromDisplay()
{ {
if (!m_OriginalMode.Windowed) /*if (!m_OriginalMode.Windowed)
{ {
m_OriginalMode.Windowed = true; m_OriginalMode.Windowed = true;
m_Driver->setMode(m_OriginalMode); m_Driver->setMode(m_OriginalMode);
m_OriginalMode.Windowed = false; m_OriginalMode.Windowed = false;
} }*/
m_Driver->setMode(m_OriginalMode); m_Driver->setMode(m_OriginalMode);
m_Driver->setWindowPos(m_OriginalWinPosX, m_OriginalWinPosY); m_Driver->setWindowPos(m_OriginalWinPosX, m_OriginalWinPosY);
m_AttachedDisplay = false; m_AttachedDisplay = false;