From 6570d0c4b7a1868ad8af4e61dd5f50bf826d9c76 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Tue, 23 Feb 2016 12:26:42 +0100 Subject: [PATCH] Add glfwSetWindowMonitor This adds the ability to switch between windowed and full screen modes, move a full screen window between monitors and update its desired resolution and refresh rate. Fixes #43. --- README.md | 2 + docs/monitor.dox | 5 +- docs/news.dox | 7 + docs/window.dox | 53 +++++- examples/boing.c | 21 +++ include/GLFW/glfw3.h | 107 ++++++++--- src/cocoa_window.m | 145 ++++++++++++-- src/internal.h | 11 ++ src/mir_window.c | 10 + src/monitor.c | 6 +- src/win32_platform.h | 4 - src/win32_window.c | 178 +++++++++++++----- src/window.c | 55 ++++-- src/wl_window.c | 10 + src/x11_window.c | 438 ++++++++++++++++++++++++------------------- tests/iconify.c | 30 +++ 16 files changed, 764 insertions(+), 318 deletions(-) diff --git a/README.md b/README.md index c65e854e..e329fb29 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ does not find Doxygen, the documentation will not be generated. - Added `glfwVulkanSupported`, `glfwGetRequiredInstanceExtensions`, `glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and `glfwCreateWindowSurface` for platform independent Vulkan support + - Added `glfwSetWindowMonitor` for switching between windowed and full screen + modes and updating the monitor and desired video mode of full screen windows - Added `glfwMaximizeWindow` and `GLFW_MAXIMIZED` for window maximization - Added `glfwFocusWindow` for giving windows input focus - Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting diff --git a/docs/monitor.dox b/docs/monitor.dox index 16fb1c82..53e88aac 100644 --- a/docs/monitor.dox +++ b/docs/monitor.dox @@ -95,8 +95,9 @@ a gamma ramp. @subsection monitor_modes Video modes GLFW generally does a good job selecting a suitable video mode when you create -a full screen window, but it is sometimes useful to know exactly which video -modes are supported. +a full screen window, change its video mode or or make a windowed one full +screen, but it is sometimes useful to know exactly which video modes are +supported. Video modes are represented as @ref GLFWvidmode structures. You can get an array of the video modes supported by a monitor with @ref glfwGetVideoModes. diff --git a/docs/news.dox b/docs/news.dox index 37c591e0..dae84309 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -26,6 +26,13 @@ Vulkan header inclusion can be selected with [GLFW_INCLUDE_VULKAN](@ref build_macros). +@subsection news_32_setwindowmonitor Window mode switching + +GLFW now supports switching between windowed and full screen modes and updating +the monitor and desired resolution and refresh rate of full screen windows with +@ref glfwSetWindowMonitor. + + @subsection news_32_maximize Window maxmimization support GLFW now supports window maximization with @ref glfwMaximizeWindow and the diff --git a/docs/window.dox b/docs/window.dox index 17bba73e..1b25c553 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -56,6 +56,10 @@ GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", glfwGetPrimaryMonito Full screen windows cover the entire display area of a monitor, have no border or decorations. +Windowed mode windows can be made full screen by setting a monitor with @ref +glfwSetWindowMonitor, and full screen ones can be made windowed by unsetting it +with the same function. + Each field of the @ref GLFWvidmode structure corresponds to a function parameter or window hint and combine to form the _desired video mode_ for that window. The supported video mode most closely matching the desired video mode will be @@ -71,9 +75,11 @@ GLFWvidmode.greenBits | `GLFW_GREEN_BITS` hint GLFWvidmode.blueBits | `GLFW_BLUE_BITS` hint GLFWvidmode.refreshRate | `GLFW_REFRESH_RATE` hint -Once you have a full screen window, you can change its resolution with @ref -glfwSetWindowSize. The new video mode will be selected and set the same way as -the video mode chosen by @ref glfwCreateWindow. +Once you have a full screen window, you can change its resolution, refresh rate +and monitor with @ref glfwSetWindowMonitor. If you just need change its +resolution you can also call @ref glfwSetWindowSize. In all cases, the new +video mode will be selected the same way as the video mode chosen by @ref +glfwCreateWindow. By default, the original video mode of the monitor will be restored and the window iconified if it loses input focus, to allow the user to switch back to @@ -101,6 +107,18 @@ glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); GLFWwindow* window = glfwCreateWindow(mode->width, mode->height, "My Title", monitor, NULL); @endcode +This also works for windowed mode windows that are made full screen. + +@code +const GLFWvidmode* mode = glfwGetVideoMode(monitor); + +glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); +@endcode + +Note that @ref glfwGetVideoMode returns the _current_ video mode of a monitor, +so if you already have a full screen window on that monitor that you want to +make windowed full screen, you need to have saved the desktop resolution before. + @subsection window_destruction Window destruction @@ -423,7 +441,7 @@ glfwSetWindowSize(window, 640, 480); @endcode For full screen windows, the specified size becomes the new resolution of the -window's *desired video mode*. The video mode most closely matching the new +window's desired video mode. The video mode most closely matching the new desired video mode is set immediately. The window is resized to fit the resolution of the set video mode. @@ -648,8 +666,31 @@ GLFWmonitor* monitor = glfwGetWindowMonitor(window); This monitor handle is one of those returned by @ref glfwGetMonitors. -For windowed mode windows, this function returns `NULL`. This is the -recommended way to tell full screen windows from windowed mode windows. +For windowed mode windows, this function returns `NULL`. This is how to tell +full screen windows from windowed mode windows. + +You can move windows between monitors or between full screen and windowed mode +with @ref glfwSetWindowMonitor. When making a window full screen on the same or +on a different monitor, specify the desired monitor, resolution and refresh +rate. The position arguments are ignored. + +@code +const GLFWvidmode* mode = glfwGetVideoMode(monitor); + +glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); +@endcode + +When making the window windowed, specify the desired position and size. The +refresh rate argument is ignored. + +@code +glfwSetWindowMonitor(window, NULL, xpos, ypos, width, height, 0); +@endcode + +This restores any previous window settings such as whether it is decorated, +floating, resizable, has size or aspect ratio limits, etc.. To restore a window +that was originally windowed to its original size and position, save these +before making it full screen and then pass them in as above. @subsection window_iconify Window iconification diff --git a/examples/boing.c b/examples/boing.c index 68eccfd5..e55d8d1c 100644 --- a/examples/boing.c +++ b/examples/boing.c @@ -89,6 +89,7 @@ typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM; typedef struct {float x; float y; float z;} vertex_t; /* Global vars */ +int windowed_xpos, windowed_ypos, windowed_width, windowed_height; int width, height; GLfloat deg_rot_y = 0.f; GLfloat deg_rot_y_inc = 2.f; @@ -238,6 +239,26 @@ void key_callback( GLFWwindow* window, int key, int scancode, int action, int mo { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE); + if (key == GLFW_KEY_ENTER && action == GLFW_PRESS && mods == GLFW_MOD_ALT) + { + if (glfwGetWindowMonitor(window)) + { + glfwSetWindowMonitor(window, NULL, + windowed_xpos, windowed_ypos, + windowed_width, windowed_height, 0); + } + else + { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + if (monitor) + { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + glfwGetWindowPos(window, &windowed_xpos, &windowed_ypos); + glfwGetWindowSize(window, &windowed_width, &windowed_height); + glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); + } + } + } } static void set_ball_pos ( GLfloat x, GLfloat y ) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 7557f1cf..d88e108a 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1718,17 +1718,17 @@ GLFWAPI void glfwWindowHint(int hint, int value); * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. * * To create a full screen window, you need to specify the monitor the window - * will cover. If no monitor is specified, windowed mode will be used. Unless - * you have a way for the user to choose a specific monitor, it is recommended - * that you pick the primary monitor. For more information on how to query - * connected monitors, see @ref monitor_monitors. + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. * * For full screen windows, the specified size becomes the resolution of the - * window's _desired video mode_. As long as a full screen window has input - * focus, the supported video mode most closely matching the desired video mode - * is set for the specified monitor. For more information about full screen - * windows, including the creation of so called _windowed full screen_ or - * _borderless full screen_ windows, see @ref window_windowed_full_screen. + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. * * By default, newly created windows use the placement recommended by the * window system. To create the window at a specific position, make it @@ -1736,8 +1736,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) * it. * - * If a full screen window has input focus, the screensaver is prohibited from - * starting. + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. * * Window systems put limits on window sizes. Very large or very small window * dimensions may be overridden by the window system on creation. Check the @@ -1751,7 +1751,7 @@ GLFWAPI void glfwWindowHint(int hint, int value); * @param[in] height The desired height, in screen coordinates, of the window. * This must be greater than zero. * @param[in] title The initial, UTF-8 encoded window title. - * @param[in] monitor The monitor to use for full screen mode, or `NULL` to use + * @param[in] monitor The monitor to use for full screen mode, or `NULL` for * windowed mode. * @param[in] share The window whose context to share resources with, or `NULL` * to not share resources. @@ -2044,11 +2044,12 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); /*! @brief Sets the size limits of the specified window. * * This function sets the size limits of the client area of the specified - * window. If the window is full screen or not resizable, this function does - * nothing. + * window. If the window is full screen, the size limits only take effect if + * once it is made windowed. If the window is not resizable, this function + * does nothing. * - * The size limits are applied immediately and may cause the window to be - * resized. + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. * * @param[in] window The window to set limits for. * @param[in] minwidth The minimum width, in screen coordinates, of the client @@ -2080,7 +2081,8 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minhe /*! @brief Sets the aspect ratio of the specified window. * * This function sets the required aspect ratio of the client area of the - * specified window. If the window is full screen or not resizable, this + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this * function does nothing. * * The aspect ratio is specified as a numerator and a denominator and both @@ -2090,8 +2092,8 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minhe * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect * ratio limit is disabled. * - * The aspect ratio is applied immediately and may cause the window to be - * resized. + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. * * @param[in] window The window to set limits for. * @param[in] numer The numerator of the desired aspect ratio, or @@ -2121,17 +2123,22 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); * This function sets the size, in screen coordinates, of the client area of * the specified window. * - * For full screen windows, this function selects and switches to the resolution - * closest to the specified size, without affecting the window's context. As - * the context is unaffected, the bit depths of the framebuffer remain - * unchanged. + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. * * The window manager may put limits on what sizes are allowed. GLFW cannot * and should not override these limits. * * @param[in] window The window to resize. - * @param[in] width The desired width of the specified window. - * @param[in] height The desired height of the specified window. + * @param[in] width The desired width, in screen coordinates, of the window + * client area. + * @param[in] height The desired height, in screen coordinates, of the window + * client area. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_PLATFORM_ERROR. @@ -2140,6 +2147,7 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); * * @sa @ref window_size * @sa glfwGetWindowSize + * @sa glfwSetWindowMonitor * * @since Added in version 1.0. * @glfw3 Added window handle parameter. @@ -2376,6 +2384,7 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* window); * @thread_safety This function must only be called from the main thread. * * @sa @ref window_monitor + * @sa glfwSetWindowMonitor * * @since Added in version 3.0. * @@ -2383,6 +2392,54 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* window); */ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); +/*! @brief Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `NULL`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `NULL`, the position, width and height are used to + * place the window client area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc.. + * + * @param[in] window The window whose monitor, size or video mode to set. + * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. + * @param[in] xpos The desired x-coordinate of the upper-left corner of the + * client area. + * @param[in] ypos The desired y-coordinate of the upper-left corner of the + * client area. + * @param[in] width The desired with, in screen coordinates, of the client area + * or video mode. + * @param[in] height The desired height, in screen coordinates, of the client + * area or video mode. + * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref window_full_screen + * @sa glfwGetWindowMonitor + * @sa glfwSetWindowSize + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + /*! @brief Returns an attribute of the specified window. * * This function returns the value of an attribute of the specified window or diff --git a/src/cocoa_window.m b/src/cocoa_window.m index c30c9409..99920d03 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -56,6 +56,26 @@ static NSCursor* getStandardCursor(int shape) return nil; } +// Returns the style mask corresponding to the window settings +// +static NSUInteger getStyleMask(_GLFWwindow* window) +{ + NSUInteger styleMask = 0; + + if (window->monitor || !window->decorated) + styleMask |= NSBorderlessWindowMask; + else + { + styleMask |= NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask; + + if (window->resizable) + styleMask |= NSResizableWindowMask; + } + + return styleMask; +} + // Center the cursor in the view of the window // static void centerCursor(_GLFWwindow *window) @@ -86,7 +106,6 @@ static GLFWbool acquireMonitor(_GLFWwindow* window) [window->ns.object setFrame:frame display:YES]; - _glfwPlatformFocusWindow(window); _glfwInputMonitorWindowChange(window->monitor, window); return status; } @@ -908,19 +927,6 @@ static GLFWbool createWindow(_GLFWwindow* window, return GLFW_FALSE; } - unsigned int styleMask = 0; - - if (window->monitor || !wndconfig->decorated) - styleMask = NSBorderlessWindowMask; - else - { - styleMask = NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask; - - if (wndconfig->resizable) - styleMask |= NSResizableWindowMask; - } - NSRect contentRect; if (window->monitor) @@ -938,7 +944,7 @@ static GLFWbool createWindow(_GLFWwindow* window, window->ns.object = [[GLFWWindow alloc] initWithContentRect:contentRect - styleMask:styleMask + styleMask:getStyleMask(window) backing:NSBackingStoreBuffered defer:NO]; @@ -948,15 +954,15 @@ static GLFWbool createWindow(_GLFWwindow* window, return GLFW_FALSE; } - if (wndconfig->resizable) - [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - if (window->monitor) [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; else { [window->ns.object center]; + if (wndconfig->resizable) + [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + if (wndconfig->floating) [window->ns.object setLevel:NSFloatingWindowLevel]; @@ -1005,6 +1011,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); if (!acquireMonitor(window)) return GLFW_FALSE; } @@ -1076,7 +1083,10 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) - acquireMonitor(window); + { + if (window->monitor->window == window) + acquireMonitor(window); + } else [window->ns.object setContentSize:NSMakeSize(width, height)]; } @@ -1174,6 +1184,103 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) [window->ns.object makeKeyAndOrderFront:nil]; } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + const NSRect contentRect = + NSMakeRect(xpos, transformY(ypos + height), width, height); + const NSRect frameRect = + [window->ns.object frameRectForContentRect:contentRect + styleMask:getStyleMask(window)]; + + [window->ns.object setFrame:frameRect display:YES]; + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + + const NSUInteger styleMask = getStyleMask(window); + [window->ns.object setStyleMask:styleMask]; + [window->ns.object makeFirstResponder:window->ns.view]; + + NSRect contentRect; + + if (monitor) + { + GLFWvidmode mode; + + _glfwPlatformGetVideoMode(window->monitor, &mode); + _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); + + contentRect = NSMakeRect(xpos, transformY(ypos + mode.height), + mode.width, mode.height); + } + else + { + contentRect = NSMakeRect(xpos, transformY(ypos + height), + width, height); + } + + NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect + styleMask:styleMask]; + [window->ns.object setFrame:frameRect display:YES]; + + if (monitor) + { + [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; + [window->ns.object setHasShadow:NO]; + + acquireMonitor(window); + } + else + { + if (window->numer != GLFW_DONT_CARE && + window->denom != GLFW_DONT_CARE) + { + [window->ns.object setContentAspectRatio:NSMakeSize(window->numer, + window->denom)]; + } + + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) + { + [window->ns.object setContentMinSize:NSMakeSize(window->minwidth, + window->minheight)]; + } + + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) + { + [window->ns.object setContentMaxSize:NSMakeSize(window->maxwidth, + window->maxheight)]; + } + + if (window->floating) + [window->ns.object setLevel:NSFloatingWindowLevel]; + else + [window->ns.object setLevel:NSNormalWindowLevel]; + + [window->ns.object setHasShadow:YES]; + } +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { return [window->ns.object isKeyWindow]; diff --git a/src/internal.h b/src/internal.h index e003ec50..ebcd8b31 100644 --- a/src/internal.h +++ b/src/internal.h @@ -339,6 +339,10 @@ struct _GLFWwindow _GLFWmonitor* monitor; _GLFWcursor* cursor; + int minwidth, minheight; + int maxwidth, maxheight; + int numer, denom; + // Window input state GLFWbool stickyKeys; GLFWbool stickyMouseButtons; @@ -694,6 +698,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window); */ void _glfwPlatformFocusWindow(_GLFWwindow* window); +/*! @copydoc glfwSetWindowMonitor + * @ingroup platform + */ +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + /*! @brief Returns whether the window is focused. * @ingroup platform */ @@ -856,6 +865,8 @@ void _glfwInputWindowDamage(_GLFWwindow* window); */ void _glfwInputWindowCloseRequest(_GLFWwindow* window); +void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor); + /*! @brief Notifies shared code of a physical key event. * @param[in] window The window that received the event. * @param[in] key The key that was pressed or released. diff --git a/src/mir_window.c b/src/mir_window.c index 5d2c145b..8e6ceb89 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -508,6 +508,16 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/monitor.c b/src/monitor.c index d21a992b..2ba4ceee 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -126,7 +126,11 @@ void _glfwInputMonitorChange(void) for (window = _glfw.windowListHead; window; window = window->next) { if (window->monitor == monitors[i]) - window->monitor = NULL; + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + } } if (_glfw.callbacks.monitor) diff --git a/src/win32_platform.h b/src/win32_platform.h index 433c4587..36e3ead2 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -197,10 +197,6 @@ typedef struct _GLFWwindowWin32 GLFWbool cursorTracked; GLFWbool iconified; - int minwidth, minheight; - int maxwidth, maxheight; - int numer, denom; - // The last received cursor position, regardless of source int cursorPosX, cursorPosY; diff --git a/src/win32_window.c b/src/win32_window.c index 5c6cc031..b120ec4e 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -42,15 +42,20 @@ static DWORD getWindowStyle(const _GLFWwindow* window) { DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; - if (window->decorated && !window->monitor) - { - style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; - - if (window->resizable) - style |= WS_MAXIMIZEBOX | WS_SIZEBOX; - } - else + if (window->monitor) style |= WS_POPUP; + else + { + if (window->decorated) + { + style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + + if (window->resizable) + style |= WS_MAXIMIZEBOX | WS_THICKFRAME; + } + else + style |= WS_POPUP; + } return style; } @@ -61,8 +66,8 @@ static DWORD getWindowExStyle(const _GLFWwindow* window) { DWORD style = WS_EX_APPWINDOW; - if (window->decorated && !window->monitor) - style |= WS_EX_WINDOWEDGE; + if (window->monitor || window->floating) + style |= WS_EX_TOPMOST; return style; } @@ -190,8 +195,7 @@ static void getFullWindowSize(DWORD style, DWORD exStyle, static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) { int xoff, yoff; - const float ratio = (float) window->win32.numer / - (float) window->win32.denom; + const float ratio = (float) window->numer / (float) window->denom; getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff); @@ -342,7 +346,8 @@ static GLFWbool acquireMonitor(_GLFWwindow* window) _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); SetWindowPos(window->win32.handle, HWND_TOPMOST, - xpos, ypos, mode.width, mode.height, SWP_NOCOPYBITS); + xpos, ypos, mode.width, mode.height, + SWP_NOACTIVATE | SWP_NOCOPYBITS); _glfwInputMonitorWindowChange(window->monitor, window); return status; @@ -639,8 +644,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, case WM_SIZING: { - if (window->win32.numer == GLFW_DONT_CARE || - window->win32.denom == GLFW_DONT_CARE) + if (window->numer == GLFW_DONT_CARE || + window->denom == GLFW_DONT_CARE) { break; } @@ -654,21 +659,24 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, int xoff, yoff; MINMAXINFO* mmi = (MINMAXINFO*) lParam; + if (window->monitor) + break; + getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), 0, 0, &xoff, &yoff); - if (window->win32.minwidth != GLFW_DONT_CARE && - window->win32.minheight != GLFW_DONT_CARE) + if (window->minwidth != GLFW_DONT_CARE && + window->minheight != GLFW_DONT_CARE) { - mmi->ptMinTrackSize.x = window->win32.minwidth + xoff; - mmi->ptMinTrackSize.y = window->win32.minheight + yoff; + mmi->ptMinTrackSize.x = window->minwidth + xoff; + mmi->ptMinTrackSize.y = window->minheight + yoff; } - if (window->win32.maxwidth != GLFW_DONT_CARE && - window->win32.maxheight != GLFW_DONT_CARE) + if (window->maxwidth != GLFW_DONT_CARE && + window->maxheight != GLFW_DONT_CARE) { - mmi->ptMaxTrackSize.x = window->win32.maxwidth + xoff; - mmi->ptMaxTrackSize.y = window->win32.maxheight + yoff; + mmi->ptMaxTrackSize.x = window->maxwidth + xoff; + mmi->ptMaxTrackSize.y = window->maxheight + yoff; } return 0; @@ -827,23 +835,8 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); } - if (wndconfig->floating && !window->monitor) - { - SetWindowPos(window->win32.handle, - HWND_TOPMOST, - 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - } - DragAcceptFiles(window->win32.handle, TRUE); - window->win32.minwidth = GLFW_DONT_CARE; - window->win32.minheight = GLFW_DONT_CARE; - window->win32.maxwidth = GLFW_DONT_CARE; - window->win32.maxheight = GLFW_DONT_CARE; - window->win32.numer = GLFW_DONT_CARE; - window->win32.denom = GLFW_DONT_CARE; - return GLFW_TRUE; } @@ -976,6 +969,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); + _glfwPlatformFocusWindow(window); if (!acquireMonitor(window)) return GLFW_FALSE; } @@ -1093,15 +1087,17 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) - acquireMonitor(window); + { + if (window->monitor->window == window) + acquireMonitor(window); + } else { - int fullWidth, fullHeight; - getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), - width, height, &fullWidth, &fullHeight); - + RECT rect = { 0, 0, width, height }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); SetWindowPos(window->win32.handle, HWND_TOP, - 0, 0, fullWidth, fullHeight, + 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); } } @@ -1112,11 +1108,6 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, { RECT area; - window->win32.minwidth = minwidth; - window->win32.minheight = minheight; - window->win32.maxwidth = maxwidth; - window->win32.maxheight = maxheight; - if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) && (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)) { @@ -1134,9 +1125,6 @@ void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom { RECT area; - window->win32.numer = numer; - window->win32.denom = denom; - if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) return; @@ -1207,6 +1195,92 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) SetFocus(window->win32.handle); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + + if (monitor) + { + GLFWvidmode mode; + DWORD style = GetWindowLongPtrW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window->decorated) + { + style &= ~WS_OVERLAPPEDWINDOW; + style |= getWindowStyle(window); + SetWindowLongPtrW(window->win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + _glfwPlatformGetVideoMode(monitor, &mode); + _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos); + + SetWindowPos(window->win32.handle, HWND_TOPMOST, + xpos, ypos, mode.width, mode.height, + flags); + + acquireMonitor(window); + } + else + { + HWND after; + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + DWORD style = GetWindowLongPtrW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; + + if (window->decorated) + { + style &= ~WS_POPUP; + style |= getWindowStyle(window); + SetWindowLongPtrW(window->win32.handle, GWL_STYLE, style); + + flags |= SWP_FRAMECHANGED; + } + + if (window->floating) + after = HWND_TOPMOST; + else + after = HWND_NOTOPMOST; + + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, after, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + flags); + } +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { return window->win32.handle == GetActiveWindow(); diff --git a/src/window.c b/src/window.c index 01f46b23..c10f9acf 100644 --- a/src/window.c +++ b/src/window.c @@ -110,6 +110,11 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window) window->callbacks.close((GLFWwindow*) window); } +void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor) +{ + window->monitor = monitor; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// @@ -154,13 +159,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, } } - if (monitor) - { - wndconfig.resizable = GLFW_TRUE; - wndconfig.visible = GLFW_TRUE; - wndconfig.focused = GLFW_TRUE; - } - if (!_glfwIsValidContextConfig(&ctxconfig)) return NULL; @@ -182,6 +180,13 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->floating = wndconfig.floating; window->cursorMode = GLFW_CURSOR_NORMAL; + window->minwidth = GLFW_DONT_CARE; + window->minheight = GLFW_DONT_CARE; + window->maxwidth = GLFW_DONT_CARE; + window->maxheight = GLFW_DONT_CARE; + window->numer = GLFW_DONT_CARE; + window->denom = GLFW_DONT_CARE; + // Save the currently current context so it can be restored later previous = _glfwPlatformGetCurrentContext(); @@ -510,11 +515,8 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height) _GLFW_REQUIRE_INIT(); - if (window->monitor) - { - window->videoMode.width = width; - window->videoMode.height = height; - } + window->videoMode.width = width; + window->videoMode.height = height; _glfwPlatformSetWindowSize(window, width, height); } @@ -528,6 +530,11 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle, _GLFW_REQUIRE_INIT(); + window->minwidth = minwidth; + window->minheight = minheight; + window->maxwidth = maxwidth; + window->maxheight = maxheight; + if (window->monitor || !window->resizable) return; @@ -543,6 +550,9 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom) _GLFW_REQUIRE_INIT(); + window->numer = numer; + window->denom = denom; + if (window->monitor || !window->resizable) return; @@ -709,6 +719,27 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle) return (GLFWmonitor*) window->monitor; } +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* wh, + GLFWmonitor* mh, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + _GLFWwindow* window = (_GLFWwindow*) wh; + _GLFWmonitor* monitor = (_GLFWmonitor*) mh; + assert(window); + + _GLFW_REQUIRE_INIT(); + + window->videoMode.width = width; + window->videoMode.height = height; + window->videoMode.refreshRate = refreshRate; + + _glfwPlatformSetWindowMonitor(window, monitor, + xpos, ypos, width, height, + refreshRate); +} + GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/wl_window.c b/src/wl_window.c index 2cc8abff..0deef6d5 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -489,6 +489,16 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) fprintf(stderr, "_glfwPlatformFocusWindow not implemented yet\n"); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + // TODO + fprintf(stderr, "_glfwPlatformSetWindowMonitor not implemented yet\n"); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { // TODO diff --git a/src/x11_window.c b/src/x11_window.c index d1f20202..aaefcd81 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -199,6 +199,145 @@ static void sendEventToWM(_GLFWwindow* window, Atom type, &event); } +// Updates the normal hints according to the window settings +// +static void updateNormalHints(_GLFWwindow* window) +{ + XSizeHints* hints = XAllocSizeHints(); + + if (!window->monitor) + { + if (window->resizable) + { + if (window->minwidth != GLFW_DONT_CARE && + window->minwidth != GLFW_DONT_CARE && + window->maxwidth != GLFW_DONT_CARE && + window->maxwidth != GLFW_DONT_CARE) + { + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = window->minwidth; + hints->min_height = window->minheight; + hints->max_width = window->maxwidth; + hints->max_height = window->maxheight; + } + + if (window->numer != GLFW_DONT_CARE && + window->denom != GLFW_DONT_CARE) + { + hints->flags |= PAspect; + hints->min_aspect.x = hints->max_aspect.x = window->numer; + hints->min_aspect.y = hints->max_aspect.y = window->denom; + } + } + else + { + int width, height; + _glfwPlatformGetWindowSize(window, &width, &height); + + hints->flags |= (PMinSize | PMaxSize); + hints->min_width = hints->max_width = width; + hints->min_height = hints->max_height = height; + } + } + + XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); + XFree(hints); +} + +// Updates the full screen status of the window +// +static void updateWindowMode(_GLFWwindow* window) +{ + updateNormalHints(window); + + if (window->monitor) + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + sendEventToWM(window, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS, + window->monitor->x11.index, + window->monitor->x11.index, + window->monitor->x11.index, + window->monitor->x11.index, + 0); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + // This is the butcher's way of removing window decorations + // Setting the override-redirect attribute on a window makes the + // window manager ignore the window completely (ICCCM, section 4) + // The good thing is that this makes undecorated full screen windows + // easy to do; the bad thing is that we have to do everything + // manually and some things (like iconify/restore) won't work at + // all, as those are tasks usually performed by the window manager + + XSetWindowAttributes attributes; + attributes.override_redirect = True; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GLFW_TRUE; + } + + if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) + { + const unsigned long value = 1; + + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); + } + } + else + { + if (_glfw.x11.xinerama.available && + _glfw.x11.NET_WM_FULLSCREEN_MONITORS) + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_FULLSCREEN_MONITORS); + } + + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) + { + sendEventToWM(window, + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_REMOVE, + _glfw.x11.NET_WM_STATE_FULLSCREEN, + 0, 1, 0); + } + else + { + XSetWindowAttributes attributes; + attributes.override_redirect = False; + XChangeWindowAttributes(_glfw.x11.display, + window->x11.handle, + CWOverrideRedirect, + &attributes); + + window->x11.overrideRedirect = GLFW_FALSE; + } + + if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) + { + XDeleteProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_BYPASS_COMPOSITOR); + } + } +} + // Splits and translates a text/uri-list into separate file paths // NOTE: This function destroys the provided string // @@ -300,84 +439,57 @@ static GLFWbool createWindow(_GLFWwindow* window, (XPointer) window); } - if (window->monitor) + if (!wndconfig->decorated) { - if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN) + struct { - // This is the butcher's way of removing window decorations - // Setting the override-redirect attribute on a window makes the - // window manager ignore the window completely (ICCCM, section 4) - // The good thing is that this makes undecorated full screen windows - // easy to do; the bad thing is that we have to do everything - // manually and some things (like iconify/restore) won't work at - // all, as those are tasks usually performed by the window manager + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } hints; - XSetWindowAttributes attributes; - attributes.override_redirect = True; - XChangeWindowAttributes(_glfw.x11.display, - window->x11.handle, - CWOverrideRedirect, - &attributes); + hints.flags = 2; // Set decorations + hints.decorations = 0; // No decorations - window->x11.overrideRedirect = GLFW_TRUE; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.MOTIF_WM_HINTS, + _glfw.x11.MOTIF_WM_HINTS, 32, + PropModeReplace, + (unsigned char*) &hints, + sizeof(hints) / sizeof(long)); + } + + if (wndconfig->floating) + { + if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE) + { + Atom value = _glfw.x11.NET_WM_STATE_ABOVE; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &value, 1); } } - else - { - if (!wndconfig->decorated) - { - struct - { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long input_mode; - unsigned long status; - } hints; - hints.flags = 2; // Set decorations - hints.decorations = 0; // No decorations + if (wndconfig->maximized && !window->monitor) + { + if (_glfw.x11.NET_WM_STATE && + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) + { + const Atom states[2] = + { + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ + }; XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.MOTIF_WM_HINTS, - _glfw.x11.MOTIF_WM_HINTS, 32, - PropModeReplace, - (unsigned char*) &hints, - sizeof(hints) / sizeof(long)); - } - - if (wndconfig->floating) - { - if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_ABOVE) - { - sendEventToWM(window, - _glfw.x11.NET_WM_STATE, - _NET_WM_STATE_ADD, - _glfw.x11.NET_WM_STATE_ABOVE, - 0, 1, 0); - } - } - - if (wndconfig->maximized) - { - if (_glfw.x11.NET_WM_STATE && - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) - { - const Atom states[2] = - { - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ - }; - - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char*) &states, 2); - } + _glfw.x11.NET_WM_STATE, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &states, 2); } } - // Declare the WM protocols supported by GLFW { int count = 0; @@ -436,27 +548,7 @@ static GLFWbool createWindow(_GLFWwindow* window, XFree(hints); } - // Set ICCCM WM_NORMAL_HINTS property (even if no parts are set) - { - XSizeHints* hints = XAllocSizeHints(); - hints->flags = 0; - - if (window->monitor) - { - hints->flags |= PPosition; - _glfwPlatformGetMonitorPos(window->monitor, &hints->x, &hints->y); - } - - if (!wndconfig->resizable) - { - hints->flags |= (PMinSize | PMaxSize); - hints->min_width = hints->max_width = wndconfig->width; - hints->min_height = hints->max_height = wndconfig->height; - } - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - XFree(hints); - } + updateNormalHints(window); // Set ICCCM WM_CLASS property // HACK: Until a mechanism for specifying the application name is added, the @@ -731,24 +823,17 @@ static GLFWbool acquireMonitor(_GLFWwindow* window) DefaultExposures); } - _glfw.x11.saver.count++; + if (!window->monitor->window) + _glfw.x11.saver.count++; status = _glfwSetVideoModeX11(window->monitor, &window->videoMode); - if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) - { - const unsigned long value = 1; - - XChangeProperty(_glfw.x11.display, window->x11.handle, - _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, - PropModeReplace, (unsigned char*) &value, 1); - } - - // Position the window over its monitor + if (window->x11.overrideRedirect) { int xpos, ypos; GLFWvidmode mode; + // Manually position the window over its monitor _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); _glfwPlatformGetVideoMode(window->monitor, &mode); @@ -756,31 +841,6 @@ static GLFWbool acquireMonitor(_GLFWwindow* window) xpos, ypos, mode.width, mode.height); } - if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS) - { - sendEventToWM(window, - _glfw.x11.NET_WM_FULLSCREEN_MONITORS, - window->monitor->x11.index, - window->monitor->x11.index, - window->monitor->x11.index, - window->monitor->x11.index, - 0); - } - - _glfwPlatformFocusWindow(window); - - if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) - { - // Ask the window manager to make the GLFW window a full screen window - // Full screen windows are undecorated and, when focused, are kept - // on top of all other windows - sendEventToWM(window, - _glfw.x11.NET_WM_STATE, - _NET_WM_STATE_ADD, - _glfw.x11.NET_WM_STATE_FULLSCREEN, - 0, 1, 0); - } - _glfwInputMonitorWindowChange(window->monitor, window); return status; } @@ -1124,9 +1184,6 @@ static void processEvent(XEvent *event) case ConfigureNotify: { - if (!window->x11.overrideRedirect && !event->xany.send_event) - return; - if (event->xconfigure.width != window->x11.width || event->xconfigure.height != window->x11.height) { @@ -1145,12 +1202,15 @@ static void processEvent(XEvent *event) if (event->xconfigure.x != window->x11.xpos || event->xconfigure.y != window->x11.ypos) { - _glfwInputWindowPos(window, - event->xconfigure.x, - event->xconfigure.y); + if (window->x11.overrideRedirect || event->xany.send_event) + { + _glfwInputWindowPos(window, + event->xconfigure.x, + event->xconfigure.y); - window->x11.xpos = event->xconfigure.x; - window->x11.ypos = event->xconfigure.y; + window->x11.xpos = event->xconfigure.x; + window->x11.ypos = event->xconfigure.y; + } } return; @@ -1459,6 +1519,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (window->monitor) { _glfwPlatformShowWindow(window); + updateWindowMode(window); if (!acquireMonitor(window)) return GLFW_FALSE; } @@ -1654,31 +1715,13 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) { if (window->monitor) { - _glfwSetVideoModeX11(window->monitor, &window->videoMode); - - if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_FULLSCREEN) - { - GLFWvidmode mode; - _glfwPlatformGetVideoMode(window->monitor, &mode); - XResizeWindow(_glfw.x11.display, window->x11.handle, - mode.width, mode.height); - } + if (window->monitor->window == window) + acquireMonitor(window); } else { if (!window->resizable) - { - // Update window size restrictions to match new window size - - XSizeHints* hints = XAllocSizeHints(); - - hints->flags |= (PMinSize | PMaxSize); - hints->min_width = hints->max_width = width; - hints->min_height = hints->max_height = height; - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - XFree(hints); - } + updateNormalHints(window); XResizeWindow(_glfw.x11.display, window->x11.handle, width, height); } @@ -1690,55 +1733,14 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { - long supplied; - XSizeHints* hints = XAllocSizeHints(); - - if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) - { - if (minwidth == GLFW_DONT_CARE || minwidth == GLFW_DONT_CARE) - hints->flags &= ~PMinSize; - else - { - hints->flags |= PMinSize; - hints->min_width = minwidth; - hints->min_height = minheight; - } - - if (maxwidth == GLFW_DONT_CARE || maxwidth == GLFW_DONT_CARE) - hints->flags &= ~PMaxSize; - else - { - hints->flags |= PMaxSize; - hints->max_width = maxwidth; - hints->max_height = maxheight; - } - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - } - - XFree(hints); + updateNormalHints(window); + XFlush(_glfw.x11.display); } void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) { - long supplied; - XSizeHints* hints = XAllocSizeHints(); - - if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) - { - if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) - hints->flags &= ~PAspect; - else - { - hints->flags |= PAspect; - hints->min_aspect.x = hints->max_aspect.x = numer; - hints->min_aspect.y = hints->max_aspect.y = denom; - } - - XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); - } - - XFree(hints); + updateNormalHints(window); + XFlush(_glfw.x11.display); } void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) @@ -1907,6 +1909,48 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window) XFlush(_glfw.x11.display); } +void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, + _GLFWmonitor* monitor, + int xpos, int ypos, + int width, int height, + int refreshRate) +{ + if (window->monitor == monitor) + { + if (monitor) + { + if (monitor->window == window) + acquireMonitor(window); + } + else + { + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, width, height); + } + + return; + } + + if (window->monitor) + releaseMonitor(window); + + _glfwInputWindowMonitorChange(window, monitor); + updateWindowMode(window); + + if (window->monitor) + { + XMapRaised(_glfw.x11.display, window->x11.handle); + acquireMonitor(window); + } + else + { + XMoveResizeWindow(_glfw.x11.display, window->x11.handle, + xpos, ypos, width, height); + } + + XFlush(_glfw.x11.display); +} + int _glfwPlatformWindowFocused(_GLFWwindow* window) { Window focused; diff --git a/tests/iconify.c b/tests/iconify.c index 3eeaf749..7990c08f 100644 --- a/tests/iconify.c +++ b/tests/iconify.c @@ -36,6 +36,8 @@ #include "getopt.h" +static int windowed_xpos, windowed_ypos, windowed_width, windowed_height; + static void usage(void) { printf("Usage: iconify [-h] [-f [-a] [-n]]\n"); @@ -74,6 +76,34 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GLFW_TRUE); break; + case GLFW_KEY_ENTER: + { + if (mods != GLFW_MOD_ALT) + return; + + if (glfwGetWindowMonitor(window)) + { + glfwSetWindowMonitor(window, NULL, + windowed_xpos, windowed_ypos, + windowed_width, windowed_height, + 0); + } + else + { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + if (monitor) + { + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + glfwGetWindowPos(window, &windowed_xpos, &windowed_ypos); + glfwGetWindowSize(window, &windowed_width, &windowed_height); + glfwSetWindowMonitor(window, monitor, + 0, 0, mode->width, mode->height, + mode->refreshRate); + } + } + + break; + } } }