From 061c273da62cd9665431c5b8ff20f889d376f423 Mon Sep 17 00:00:00 2001 From: Eden Salomon Date: Thu, 22 Oct 2015 20:02:40 +0300 Subject: [PATCH] Add option to toggle between fullscreen and window mode on Win32 --- include/GLFW/glfw3.h | 13 ++++++ src/internal.h | 7 ++++ src/wgl_context.c | 4 +- src/win32_window.c | 94 ++++++++++++++++++++++++++------------------ src/window.c | 37 +++++++++++------ 5 files changed, 104 insertions(+), 51 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 965dbe7a2..7254cab0d 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -614,6 +614,7 @@ extern "C" { #define GLFW_DECORATED 0x00020005 #define GLFW_AUTO_ICONIFY 0x00020006 #define GLFW_FLOATING 0x00020007 +#define GLFW_FULLSCREEN 0x00020008 #define GLFW_RED_BITS 0x00021001 #define GLFW_GREEN_BITS 0x00021002 @@ -2101,6 +2102,18 @@ GLFWAPI void glfwShowWindow(GLFWwindow* window); */ GLFWAPI void glfwHideWindow(GLFWwindow* window); +/*! @brief Toggles between fullscreen and windowed mode on the specified window. + * + * The functions enters fullscreen mode if the specified window was previously + * in windowed mode. If the window is already in fullscreen mode, the fuctions restores + * the monitor video mode and the specified window switches back to windowed mode. + * + * @param[in] window The window to toggle his mode. + * + * @ingroup window + */ +GLFWAPI void glfwToggleWindowFullscreen(GLFWwindow* window); + /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is diff --git a/src/internal.h b/src/internal.h index 56647a31c..a25c2daf8 100644 --- a/src/internal.h +++ b/src/internal.h @@ -178,6 +178,7 @@ struct _GLFWwndconfig GLFWbool focused; GLFWbool autoIconify; GLFWbool floating; + GLFWbool fullscreen; _GLFWmonitor* monitor; }; @@ -245,6 +246,7 @@ struct _GLFWwindow GLFWbool autoIconify; GLFWbool floating; GLFWbool closed; + GLFWbool fullscreen; void* userPointer; GLFWvidmode videoMode; _GLFWmonitor* monitor; @@ -584,6 +586,11 @@ void _glfwPlatformUnhideWindow(_GLFWwindow* window); */ void _glfwPlatformHideWindow(_GLFWwindow* window); +/*! @copydoc glfwToggleWindowFullscreen + * @ingroup platform + */ +void _glfwPlatformToggleWindowFullscreen(_GLFWwindow* window); + /*! @brief Returns whether the window is focused. * @ingroup platform */ diff --git a/src/wgl_context.c b/src/wgl_context.c index 0bce17e78..ebb8e398f 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -600,7 +600,7 @@ void _glfwPlatformMakeContextCurrent(_GLFWwindow* window) void _glfwPlatformSwapBuffers(_GLFWwindow* window) { // HACK: Use DwmFlush when desktop composition is enabled - if (_glfwIsCompositionEnabled() && !window->monitor) + if (_glfwIsCompositionEnabled() && !window->fullscreen) { int count = abs(window->wgl.interval); while (count--) @@ -618,7 +618,7 @@ void _glfwPlatformSwapInterval(int interval) // HACK: Disable WGL swap interval when desktop composition is enabled to // avoid interfering with DWM vsync - if (_glfwIsCompositionEnabled() && !window->monitor) + if (_glfwIsCompositionEnabled() && !window->fullscreen) interval = 0; if (window->wgl.EXT_swap_control) diff --git a/src/win32_window.c b/src/win32_window.c index 7f8f380f5..049bb30a0 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -44,7 +44,7 @@ static DWORD getWindowStyle(const _GLFWwindow* window) { DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; - if (window->decorated && !window->monitor) + if (window->decorated && !window->fullscreen) { style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; @@ -63,7 +63,7 @@ static DWORD getWindowExStyle(const _GLFWwindow* window) { DWORD style = WS_EX_APPWINDOW; - if (window->decorated && !window->monitor) + if (window->decorated && !window->fullscreen) style |= WS_EX_WINDOWEDGE; return style; @@ -224,15 +224,24 @@ static int translateKey(WPARAM wParam, LPARAM lParam) return _glfw.win32.publicKeys[HIWORD(lParam) & 0x1FF]; } +static void updateWindowStyle(_GLFWwindow* window) +{ + SetWindowLongPtr(window->win32.handle, GWL_EXSTYLE, getWindowExStyle(window)); + SetWindowLongPtr(window->win32.handle, GWL_STYLE, getWindowStyle(window)); + + _glfwPlatformShowWindow(window); +} + // Enter full screen mode // static GLFWbool enterFullscreenMode(_GLFWwindow* window) { GLFWvidmode mode; - GLFWbool status; int xpos, ypos; - status = _glfwSetVideoMode(window->monitor, &window->videoMode); + window->fullscreen = _glfwSetVideoMode(window->monitor, &window->videoMode); + + updateWindowStyle(window); _glfwPlatformGetVideoMode(window->monitor, &mode); _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); @@ -240,7 +249,7 @@ static GLFWbool enterFullscreenMode(_GLFWwindow* window) SetWindowPos(window->win32.handle, HWND_TOPMOST, xpos, ypos, mode.width, mode.height, SWP_NOCOPYBITS); - return status; + return window->fullscreen; } // Leave full screen mode @@ -248,6 +257,10 @@ static GLFWbool enterFullscreenMode(_GLFWwindow* window) static void leaveFullscreenMode(_GLFWwindow* window) { _glfwRestoreVideoMode(window->monitor); + + window->fullscreen = GLFW_FALSE; + + updateWindowStyle(window); } // Window callback function (handles window events) @@ -280,7 +293,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (window->cursorMode == GLFW_CURSOR_DISABLED) _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL); - if (window->monitor && window->autoIconify) + if (window->fullscreen && window->autoIconify) _glfwPlatformIconifyWindow(window); _glfwInputWindowFocus(window, GLFW_FALSE); @@ -294,7 +307,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case SC_SCREENSAVE: case SC_MONITORPOWER: { - if (window->monitor) + if (window->fullscreen) { // We are running in full screen mode, so disallow // screen saver and screen blanking @@ -508,8 +521,13 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, if (!window->win32.iconified && wParam == SIZE_MINIMIZED) { window->win32.iconified = GLFW_TRUE; - if (window->monitor) + + if (window->fullscreen) leaveFullscreenMode(window); + + // We don't really toggle fullscreen, + // just temporally restore monitor video mode + window->fullscreen = GLFW_TRUE; _glfwInputWindowIconify(window, GLFW_TRUE); } @@ -517,7 +535,9 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED)) { window->win32.iconified = GLFW_FALSE; - if (window->monitor) + + // check if we should go back to fullscreen mode + if (window->fullscreen) enterFullscreenMode(window); _glfwInputWindowIconify(window, GLFW_FALSE); @@ -673,7 +693,7 @@ static GLFWbool createWindow(_GLFWwindow* window, int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; - if (wndconfig->monitor) + if (wndconfig->fullscreen) { GLFWvidmode mode; @@ -732,7 +752,7 @@ static GLFWbool createWindow(_GLFWwindow* window, WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } - if (wndconfig->floating && !wndconfig->monitor) + if (wndconfig->floating && !wndconfig->fullscreen) { SetWindowPos(window->win32.handle, HWND_TOPMOST, @@ -868,17 +888,12 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!createWindow(window, wndconfig, ctxconfig, fbconfig)) return GLFW_FALSE; } - - if (window->monitor) + + if (wndconfig->fullscreen) { - // the following function calls ShowWindow - // which sends WM_SETFOCUS to windowProc() - // Which then enters fullscreen mode if autoIconify is enabled (win32_window.c : line 283) _glfwPlatformShowWindow(window); - if (!window->autoIconify) { // add this to prevent entering full screen mode twice when autoIconify == true - if (!enterFullscreenMode(window)) - return GLFW_FALSE; - } + if (!enterFullscreenMode(window)) + return GLFW_FALSE; } return GLFW_TRUE; @@ -886,7 +901,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, void _glfwPlatformDestroyWindow(_GLFWwindow* window) { - if (window->monitor) + if (window->fullscreen) leaveFullscreenMode(window); destroyWindow(window); @@ -939,7 +954,7 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { - if (window->monitor) + if (window->fullscreen) enterFullscreenMode(window); else { @@ -1032,20 +1047,7 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window) ShowWindow(window->win32.handle, SW_RESTORE); } -void _glfwPlatformShowWindow(_GLFWwindow* window) -{ - ShowWindow(window->win32.handle, SW_SHOW); - - // Consider separating the following function calls to a different function? - // e.g. RequestFocus(_GLFWwindow* window) (any of these might fail) - BringWindowToTop(window->win32.handle); - SetForegroundWindow(window->win32.handle); - SetFocus(window->win32.handle); -} - -/* one example of separation */ - -int _glfwPlatformGrabFocus(_GLFWwindow* window) +int WindowGrabFocus(_GLFWwindow* window) { if (!BringWindowToTop(window->win32.handle)) return GLFW_FALSE; @@ -1056,11 +1058,11 @@ int _glfwPlatformGrabFocus(_GLFWwindow* window) return GLFW_FALSE; } -void _glfwPlatformRequestFocus(_GLFWwindow* window) +void WindowRequestFocus(_GLFWwindow* window) { // The following can be used to flash the taskbar icon // if any of the focus related functions fail - if (!_glfwPlatformGrabFocus(window)) { + if (!WindowGrabFocus(window)) { // create a taskbar notification ("flash") FLASHWINFO info; info.cbSize = sizeof(FLASHWINFO); @@ -1073,6 +1075,13 @@ void _glfwPlatformRequestFocus(_GLFWwindow* window) } } +void _glfwPlatformShowWindow(_GLFWwindow* window) +{ + ShowWindow(window->win32.handle, SW_SHOW); + WindowRequestFocus(window); +} + + void _glfwPlatformUnhideWindow(_GLFWwindow* window) { ShowWindow(window->win32.handle, SW_SHOW); @@ -1083,6 +1092,15 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) ShowWindow(window->win32.handle, SW_HIDE); } +void _glfwPlatformToggleWindowFullscreen(_GLFWwindow* window) +{ + if (window->fullscreen) { + leaveFullscreenMode(window); + } else { + enterFullscreenMode(window); + } +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { return window->win32.handle == GetActiveWindow(); diff --git a/src/window.c b/src/window.c index 1b2e1f208..1f9cd7bd7 100644 --- a/src/window.c +++ b/src/window.c @@ -139,10 +139,10 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, wndconfig.width = width; wndconfig.height = height; wndconfig.title = title; - wndconfig.monitor = (_GLFWmonitor*) monitor; + wndconfig.monitor = (_GLFWmonitor*) (monitor ? monitor : glfwGetPrimaryMonitor()); ctxconfig.share = (_GLFWwindow*) share; - if (wndconfig.monitor) + if (wndconfig.fullscreen) { wndconfig.resizable = GLFW_TRUE; wndconfig.visible = GLFW_TRUE; @@ -208,7 +208,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, // Restore the previously current context (or NULL) _glfwPlatformMakeContextCurrent(previous); - if (wndconfig.monitor) + if (wndconfig.fullscreen) { int width, height; _glfwPlatformGetWindowSize(window, &width, &height); @@ -249,6 +249,7 @@ void glfwDefaultWindowHints(void) _glfw.hints.window.decorated = GLFW_TRUE; _glfw.hints.window.focused = GLFW_TRUE; _glfw.hints.window.autoIconify = GLFW_TRUE; + _glfw.hints.window.fullscreen = GLFW_FALSE; // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, // double buffered @@ -324,6 +325,9 @@ GLFWAPI void glfwWindowHint(int target, int hint) case GLFW_FOCUSED: _glfw.hints.window.focused = hint ? GLFW_TRUE : GLFW_FALSE; break; + case GLFW_FULLSCREEN: + _glfw.hints.window.fullscreen = hint ? GLFW_TRUE : GLFW_FALSE; + break; case GLFW_AUTO_ICONIFY: _glfw.hints.window.autoIconify = hint ? GLFW_TRUE : GLFW_FALSE; break; @@ -443,7 +447,7 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* handle, int xpos, int ypos) _GLFW_REQUIRE_INIT(); - if (window->monitor) + if (window->fullscreen) { _glfwInputError(GLFW_INVALID_VALUE, "Full screen windows cannot be moved"); @@ -472,7 +476,7 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) _GLFW_REQUIRE_INIT(); - if (window->monitor) + if (window->fullscreen) { window->videoMode.width = width; window->videoMode.height = height; @@ -489,7 +493,7 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, _GLFW_REQUIRE_INIT(); - if (window->monitor || !window->resizable) + if (window->fullscreen || !window->resizable) return; _glfwPlatformSetWindowSizeLimits(window, @@ -503,7 +507,7 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) _GLFW_REQUIRE_INIT(); - if (window->monitor || !window->resizable) + if (window->fullscreen || !window->resizable) return; if (!denom) @@ -567,8 +571,8 @@ GLFWAPI void glfwShowWindow(GLFWwindow* handle) _GLFW_REQUIRE_INIT(); - if (window->monitor) - return; + if (window->fullscreen) + _glfwPlatformToggleWindowFullscreen(window); _glfwPlatformShowWindow(window); } @@ -579,12 +583,21 @@ GLFWAPI void glfwHideWindow(GLFWwindow* handle) _GLFW_REQUIRE_INIT(); - if (window->monitor) - return; + if (window->fullscreen) + _glfwPlatformToggleWindowFullscreen(window); _glfwPlatformHideWindow(window); } +GLFWAPI void glfwToggleWindowFullscreen(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + + _GLFW_REQUIRE_INIT(); + + _glfwPlatformToggleWindowFullscreen(window); +} + GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) { _GLFWwindow* window = (_GLFWwindow*) handle; @@ -605,6 +618,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->decorated; case GLFW_FLOATING: return window->floating; + case GLFW_FULLSCREEN: + return window->fullscreen; case GLFW_CLIENT_API: return window->context.api; case GLFW_CONTEXT_VERSION_MAJOR: