diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 13d0a52e9..4bab79660 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1635,10 +1635,34 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * * @note This function may only be called from the main thread. * + * @sa glfwSetWindowMonitor + * * @ingroup window */ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); +/*! @brief Sets the monitor that the window uses for full screen mode. + * + * This function sets the monitor that the specified window uses for full + * screen mode, or if no monitor is specified, makes it windowed mode. + * + * The specified width and height are used as the new size of a windowed mode + * window or, if a monitor is specified, used to find a suitable video mode for + * the monitor the window will become full screen on. + * + * @param[in] window The window whose monitor to set or unset. + * @param[in] monitor The monitor, or `NULL` to make it windowed mode. + * @param[in] width The desired width, in screen coordinates, of the window or + * video mode. + * @param[in] height The desired height, in screen coordinates, of the window or + * video mode. + * + * @sa glfwGetWindowMonitor + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int width, int height); + /*! @brief Returns an attribute of the specified window. * * This function returns an attribute of the specified window. There are many diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 0eff37ac2..94a4720fb 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1153,6 +1153,12 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) _glfwInputWindowVisibility(window, GL_FALSE); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int width, int height) +{ +} + void _glfwPlatformPollEvents(void) { for (;;) diff --git a/src/internal.h b/src/internal.h index 252f20c00..5db7dc9de 100644 --- a/src/internal.h +++ b/src/internal.h @@ -565,6 +565,11 @@ void _glfwPlatformShowWindow(_GLFWwindow* window); */ void _glfwPlatformHideWindow(_GLFWwindow* window); +/*! @copydoc glfwSetWindowMonitor + * @ingroup platform + */ +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int width, int height); + /*! @copydoc glfwPollEvents * @ingroup platform */ @@ -746,6 +751,10 @@ void _glfwInputCursorEnter(_GLFWwindow* window, int entered); */ void _glfwInputMonitorChange(void); +/*! @ingroup event + */ +void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor); + /*! @brief Notifies shared code of an error. * @param[in] error The error code most suitable for the error. * @param[in] format The `printf` style format string of the error diff --git a/src/monitor.c b/src/monitor.c index eccbd4333..4c710b8f5 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -156,6 +156,11 @@ void _glfwInputMonitorChange(void) _glfwFreeMonitors(monitors, monitorCount); } +void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor) +{ + window->monitor = monitor; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// diff --git a/src/win32_window.c b/src/win32_window.c index 57e17660a..f23cbe8f6 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -35,6 +35,37 @@ #define _GLFW_KEY_INVALID -2 +// Returns the window style for the specified window configuration +// +static getWindowStyle(const _GLFWwndconfig* wndconfig) +{ + DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + + if (wndconfig->decorated && wndconfig->monitor == NULL) + { + style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + + if (wndconfig->resizable) + style |= WS_MAXIMIZEBOX | WS_SIZEBOX; + } + else + style |= WS_POPUP; + + return style; +} + +// Returns the extended window style for the specified window configuration +// +static getWindowExStyle(const _GLFWwndconfig* wndconfig) +{ + DWORD style = WS_EX_APPWINDOW; + + if (wndconfig->decorated && wndconfig->monitor == NULL) + style |= WS_EX_WINDOWEDGE; + + return style; +} + // Updates the cursor clip rect // static void updateClipRect(_GLFWwindow* window) @@ -885,38 +916,23 @@ static int createWindow(_GLFWwindow* window, int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; - window->win32.dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; - window->win32.dwExStyle = WS_EX_APPWINDOW; + window->win32.dwStyle = getWindowStyle(wndconfig); + window->win32.dwExStyle = getWindowExStyle(wndconfig); if (window->monitor) { - window->win32.dwStyle |= WS_POPUP; - _glfwPlatformGetMonitorPos(wndconfig->monitor, &xpos, &ypos); fullWidth = wndconfig->width; fullHeight = wndconfig->height; } else { - if (wndconfig->decorated) - { - window->win32.dwStyle |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; - - if (wndconfig->resizable) - { - window->win32.dwStyle |= WS_MAXIMIZEBOX | WS_SIZEBOX; - window->win32.dwExStyle |= WS_EX_WINDOWEDGE; - } - } - else - window->win32.dwStyle |= WS_POPUP; - xpos = CW_USEDEFAULT; ypos = CW_USEDEFAULT; getFullWindowSize(window, - wndconfig->width, wndconfig->height, - &fullWidth, &fullHeight); + wndconfig->width, wndconfig->height, + &fullWidth, &fullHeight); } wideTitle = _glfwCreateWideStringFromUTF8(wndconfig->title); @@ -1183,6 +1199,55 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) ShowWindow(window->win32.handle, SW_HIDE); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int width, int height) +{ + if (window->monitor) + _glfwRestoreVideoMode(window->monitor); + + _glfwInputWindowMonitorChange(window, monitor); + + // Update window styles + { + _GLFWwndconfig wndconfig; + wndconfig.resizable = window->resizable; + wndconfig.decorated = window->decorated; + wndconfig.monitor = monitor; + + window->win32.dwStyle = getWindowStyle(&wndconfig); + window->win32.dwExStyle = getWindowExStyle(&wndconfig); + + SetWindowLongPtr(window->win32.handle, + GWL_STYLE, window->win32.dwStyle); + SetWindowLongPtr(window->win32.handle, + GWL_EXSTYLE, window->win32.dwExStyle); + } + + if (window->monitor) + { + GLFWvidmode mode; + int xpos, ypos; + + _glfwSetVideoMode(window->monitor, &window->videoMode); + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + xpos, ypos, mode.width, mode.height, + SWP_FRAMECHANGED); + } + else + { + int fullWidth, fullHeight; + getFullWindowSize(window, width, height, &fullWidth, &fullHeight); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + 0, 0, fullWidth, fullHeight, + SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + } +} + void _glfwPlatformPollEvents(void) { MSG msg; diff --git a/src/window.c b/src/window.c index 448cf3625..3c201117c 100644 --- a/src/window.c +++ b/src/window.c @@ -498,11 +498,8 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) if (window->iconified) return; - if (window->monitor) - { - window->videoMode.width = width; - window->videoMode.height = height; - } + window->videoMode.width = width; + window->videoMode.height = height; _glfwPlatformSetWindowSize(window, width, height); } @@ -636,6 +633,29 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) return (GLFWmonitor*) window->monitor; } +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, + GLFWmonitor* mh, + int width, int height) +{ + _GLFWwindow* window = (_GLFWwindow*) wh; + _GLFWmonitor* monitor = (_GLFWmonitor*) mh; + _GLFW_REQUIRE_INIT(); + + if (window->monitor == monitor) + { + glfwSetWindowSize(wh, width, height); + return; + } + + if (window->iconified) + return; + + window->videoMode.width = width; + window->videoMode.height = height; + + _glfwPlatformSetWindowMonitor(window, monitor, width, height); +} + GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/x11_window.c b/src/x11_window.c index 3d1863d56..c6895e3b5 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1373,6 +1373,19 @@ void _glfwPlatformHideWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int width, int height) +{ + if (window->monitor) + leaveFullscreenMode(window); + + _glfwInputWindowMonitorChange(window, monitor); + + if (window->monitor) + enterFullscreenMode(window); +} + void _glfwPlatformPollEvents(void) { int count = XPending(_glfw.x11.display); diff --git a/tests/events.c b/tests/events.c index 7f30652c0..cc22bfc91 100644 --- a/tests/events.c +++ b/tests/events.c @@ -378,6 +378,32 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, printf("(( closing %s ))\n", slot->closeable ? "enabled" : "disabled"); break; } + + case GLFW_KEY_ENTER: + { + if (mods == GLFW_MOD_ALT) + { + GLFWmonitor* monitor = glfwGetWindowMonitor(window); + if (monitor) + { + printf("(( switching to windowed mode ))\n"); + glfwSetWindowMonitor(window, NULL, 640, 480); + } + else + { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + printf("(( switching to %ix%i full screen mode on %s ))\n", + mode->width, mode->height, + glfwGetMonitorName(monitor)); + + glfwSetWindowMonitor(window, monitor, mode->width, mode->height); + } + } + + break; + } } }