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.
This commit is contained in:
Camilla Berglund 2016-02-23 12:26:42 +01:00
parent fb8a31ba3f
commit 6570d0c4b7
16 changed files with 764 additions and 318 deletions

View File

@ -77,6 +77,8 @@ does not find Doxygen, the documentation will not be generated.
- Added `glfwVulkanSupported`, `glfwGetRequiredInstanceExtensions`, - Added `glfwVulkanSupported`, `glfwGetRequiredInstanceExtensions`,
`glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and `glfwGetInstanceProcAddress`, `glfwGetPhysicalDevicePresentationSupport` and
`glfwCreateWindowSurface` for platform independent Vulkan support `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 `glfwMaximizeWindow` and `GLFW_MAXIMIZED` for window maximization
- Added `glfwFocusWindow` for giving windows input focus - Added `glfwFocusWindow` for giving windows input focus
- Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting - Added `glfwSetWindowSizeLimits` and `glfwSetWindowAspectRatio` for setting

View File

@ -95,8 +95,9 @@ a gamma ramp.
@subsection monitor_modes Video modes @subsection monitor_modes Video modes
GLFW generally does a good job selecting a suitable video mode when you create 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 a full screen window, change its video mode or or make a windowed one full
modes are supported. 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 Video modes are represented as @ref GLFWvidmode structures. You can get an
array of the video modes supported by a monitor with @ref glfwGetVideoModes. array of the video modes supported by a monitor with @ref glfwGetVideoModes.

View File

@ -26,6 +26,13 @@ Vulkan header inclusion can be selected with
[GLFW_INCLUDE_VULKAN](@ref build_macros). [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 @subsection news_32_maximize Window maxmimization support
GLFW now supports window maximization with @ref glfwMaximizeWindow and the GLFW now supports window maximization with @ref glfwMaximizeWindow and the

View File

@ -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 Full screen windows cover the entire display area of a monitor, have no border
or decorations. 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 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. 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 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.blueBits | `GLFW_BLUE_BITS` hint
GLFWvidmode.refreshRate | `GLFW_REFRESH_RATE` hint GLFWvidmode.refreshRate | `GLFW_REFRESH_RATE` hint
Once you have a full screen window, you can change its resolution with @ref Once you have a full screen window, you can change its resolution, refresh rate
glfwSetWindowSize. The new video mode will be selected and set the same way as and monitor with @ref glfwSetWindowMonitor. If you just need change its
the video mode chosen by @ref glfwCreateWindow. 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 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 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); GLFWwindow* window = glfwCreateWindow(mode->width, mode->height, "My Title", monitor, NULL);
@endcode @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 @subsection window_destruction Window destruction
@ -423,7 +441,7 @@ glfwSetWindowSize(window, 640, 480);
@endcode @endcode
For full screen windows, the specified size becomes the new resolution of the 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 desired video mode is set immediately. The window is resized to fit the
resolution of the set video mode. 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. This monitor handle is one of those returned by @ref glfwGetMonitors.
For windowed mode windows, this function returns `NULL`. This is the For windowed mode windows, this function returns `NULL`. This is how to tell
recommended way to tell full screen windows from windowed mode windows. 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 @subsection window_iconify Window iconification

View File

@ -89,6 +89,7 @@ typedef enum { DRAW_BALL, DRAW_BALL_SHADOW } DRAW_BALL_ENUM;
typedef struct {float x; float y; float z;} vertex_t; typedef struct {float x; float y; float z;} vertex_t;
/* Global vars */ /* Global vars */
int windowed_xpos, windowed_ypos, windowed_width, windowed_height;
int width, height; int width, height;
GLfloat deg_rot_y = 0.f; GLfloat deg_rot_y = 0.f;
GLfloat deg_rot_y_inc = 2.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) if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE); 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 ) static void set_ball_pos ( GLfloat x, GLfloat y )

View File

@ -1718,17 +1718,17 @@ GLFWAPI void glfwWindowHint(int hint, int value);
* glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize.
* *
* To create a full screen window, you need to specify the monitor the window * 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 * will cover. If no monitor is specified, the window will be windowed mode.
* you have a way for the user to choose a specific monitor, it is recommended * Unless you have a way for the user to choose a specific monitor, it is
* that you pick the primary monitor. For more information on how to query * recommended that you pick the primary monitor. For more information on how
* connected monitors, see @ref monitor_monitors. * to query connected monitors, see @ref monitor_monitors.
* *
* For full screen windows, the specified size becomes the resolution of the * 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 * window's _desired video mode_. As long as a full screen window is not
* focus, the supported video mode most closely matching the desired video mode * iconified, the supported video mode most closely matching the desired video
* is set for the specified monitor. For more information about full screen * mode is set for the specified monitor. For more information about full
* windows, including the creation of so called _windowed full screen_ or * screen windows, including the creation of so called _windowed full screen_
* _borderless full screen_ windows, see @ref window_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 * By default, newly created windows use the placement recommended by the
* window system. To create the window at a specific position, make it * 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) * hint, set its [position](@ref window_pos) and then [show](@ref window_hide)
* it. * it.
* *
* If a full screen window has input focus, the screensaver is prohibited from * As long as at least one full screen window is not iconified, the screensaver
* starting. * is prohibited from starting.
* *
* Window systems put limits on window sizes. Very large or very small window * 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 * 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. * @param[in] height The desired height, in screen coordinates, of the window.
* This must be greater than zero. * This must be greater than zero.
* @param[in] title The initial, UTF-8 encoded window title. * @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. * windowed mode.
* @param[in] share The window whose context to share resources with, or `NULL` * @param[in] share The window whose context to share resources with, or `NULL`
* to not share resources. * 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. /*! @brief Sets the size limits of the specified window.
* *
* This function sets the size limits of the client area of the specified * 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 * window. If the window is full screen, the size limits only take effect if
* nothing. * 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 * The size limits are applied immediately to a windowed mode window and may
* resized. * cause it to be resized.
* *
* @param[in] window The window to set limits for. * @param[in] window The window to set limits for.
* @param[in] minwidth The minimum width, in screen coordinates, of the client * @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. /*! @brief Sets the aspect ratio of the specified window.
* *
* This function sets the required aspect ratio of the client area of the * 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. * function does nothing.
* *
* The aspect ratio is specified as a numerator and a denominator and both * 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 * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect
* ratio limit is disabled. * ratio limit is disabled.
* *
* The aspect ratio is applied immediately and may cause the window to be * The aspect ratio is applied immediately to a windowed mode window and may
* resized. * cause it to be resized.
* *
* @param[in] window The window to set limits for. * @param[in] window The window to set limits for.
* @param[in] numer The numerator of the desired aspect ratio, or * @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 * This function sets the size, in screen coordinates, of the client area of
* the specified window. * the specified window.
* *
* For full screen windows, this function selects and switches to the resolution * For full screen windows, this function updates the resolution of its desired
* closest to the specified size, without affecting the window's context. As * video mode and switches to the video mode closest to it, without affecting
* the context is unaffected, the bit depths of the framebuffer remain * the window's context. As the context is unaffected, the bit depths of the
* unchanged. * 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 * The window manager may put limits on what sizes are allowed. GLFW cannot
* and should not override these limits. * and should not override these limits.
* *
* @param[in] window The window to resize. * @param[in] window The window to resize.
* @param[in] width The desired width of the specified window. * @param[in] width The desired width, in screen coordinates, of the window
* @param[in] height The desired height of the specified 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 * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR. * GLFW_PLATFORM_ERROR.
@ -2140,6 +2147,7 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom);
* *
* @sa @ref window_size * @sa @ref window_size
* @sa glfwGetWindowSize * @sa glfwGetWindowSize
* @sa glfwSetWindowMonitor
* *
* @since Added in version 1.0. * @since Added in version 1.0.
* @glfw3 Added window handle parameter. * @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. * @thread_safety This function must only be called from the main thread.
* *
* @sa @ref window_monitor * @sa @ref window_monitor
* @sa glfwSetWindowMonitor
* *
* @since Added in version 3.0. * @since Added in version 3.0.
* *
@ -2383,6 +2392,54 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* window);
*/ */
GLFWAPI GLFWmonitor* glfwGetWindowMonitor(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. /*! @brief Returns an attribute of the specified window.
* *
* This function returns the value of an attribute of the specified window or * This function returns the value of an attribute of the specified window or

View File

@ -56,6 +56,26 @@ static NSCursor* getStandardCursor(int shape)
return nil; 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 // Center the cursor in the view of the window
// //
static void centerCursor(_GLFWwindow *window) static void centerCursor(_GLFWwindow *window)
@ -86,7 +106,6 @@ static GLFWbool acquireMonitor(_GLFWwindow* window)
[window->ns.object setFrame:frame display:YES]; [window->ns.object setFrame:frame display:YES];
_glfwPlatformFocusWindow(window);
_glfwInputMonitorWindowChange(window->monitor, window); _glfwInputMonitorWindowChange(window->monitor, window);
return status; return status;
} }
@ -908,19 +927,6 @@ static GLFWbool createWindow(_GLFWwindow* window,
return GLFW_FALSE; 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; NSRect contentRect;
if (window->monitor) if (window->monitor)
@ -938,7 +944,7 @@ static GLFWbool createWindow(_GLFWwindow* window,
window->ns.object = [[GLFWWindow alloc] window->ns.object = [[GLFWWindow alloc]
initWithContentRect:contentRect initWithContentRect:contentRect
styleMask:styleMask styleMask:getStyleMask(window)
backing:NSBackingStoreBuffered backing:NSBackingStoreBuffered
defer:NO]; defer:NO];
@ -948,15 +954,15 @@ static GLFWbool createWindow(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
if (wndconfig->resizable)
[window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
if (window->monitor) if (window->monitor)
[window->ns.object setLevel:NSMainMenuWindowLevel + 1]; [window->ns.object setLevel:NSMainMenuWindowLevel + 1];
else else
{ {
[window->ns.object center]; [window->ns.object center];
if (wndconfig->resizable)
[window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
if (wndconfig->floating) if (wndconfig->floating)
[window->ns.object setLevel:NSFloatingWindowLevel]; [window->ns.object setLevel:NSFloatingWindowLevel];
@ -1005,6 +1011,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (window->monitor) if (window->monitor)
{ {
_glfwPlatformShowWindow(window); _glfwPlatformShowWindow(window);
_glfwPlatformFocusWindow(window);
if (!acquireMonitor(window)) if (!acquireMonitor(window))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1076,7 +1083,10 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{ {
if (window->monitor) if (window->monitor)
acquireMonitor(window); {
if (window->monitor->window == window)
acquireMonitor(window);
}
else else
[window->ns.object setContentSize:NSMakeSize(width, height)]; [window->ns.object setContentSize:NSMakeSize(width, height)];
} }
@ -1174,6 +1184,103 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
[window->ns.object makeKeyAndOrderFront:nil]; [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) int _glfwPlatformWindowFocused(_GLFWwindow* window)
{ {
return [window->ns.object isKeyWindow]; return [window->ns.object isKeyWindow];

View File

@ -339,6 +339,10 @@ struct _GLFWwindow
_GLFWmonitor* monitor; _GLFWmonitor* monitor;
_GLFWcursor* cursor; _GLFWcursor* cursor;
int minwidth, minheight;
int maxwidth, maxheight;
int numer, denom;
// Window input state // Window input state
GLFWbool stickyKeys; GLFWbool stickyKeys;
GLFWbool stickyMouseButtons; GLFWbool stickyMouseButtons;
@ -694,6 +698,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window);
*/ */
void _glfwPlatformFocusWindow(_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. /*! @brief Returns whether the window is focused.
* @ingroup platform * @ingroup platform
*/ */
@ -856,6 +865,8 @@ void _glfwInputWindowDamage(_GLFWwindow* window);
*/ */
void _glfwInputWindowCloseRequest(_GLFWwindow* window); void _glfwInputWindowCloseRequest(_GLFWwindow* window);
void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor);
/*! @brief Notifies shared code of a physical key event. /*! @brief Notifies shared code of a physical key event.
* @param[in] window The window that received the event. * @param[in] window The window that received the event.
* @param[in] key The key that was pressed or released. * @param[in] key The key that was pressed or released.

View File

@ -508,6 +508,16 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
"Mir: Unsupported function %s", __PRETTY_FUNCTION__); "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) int _glfwPlatformWindowFocused(_GLFWwindow* window)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,

View File

@ -126,7 +126,11 @@ void _glfwInputMonitorChange(void)
for (window = _glfw.windowListHead; window; window = window->next) for (window = _glfw.windowListHead; window; window = window->next)
{ {
if (window->monitor == monitors[i]) 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) if (_glfw.callbacks.monitor)

View File

@ -197,10 +197,6 @@ typedef struct _GLFWwindowWin32
GLFWbool cursorTracked; GLFWbool cursorTracked;
GLFWbool iconified; GLFWbool iconified;
int minwidth, minheight;
int maxwidth, maxheight;
int numer, denom;
// The last received cursor position, regardless of source // The last received cursor position, regardless of source
int cursorPosX, cursorPosY; int cursorPosX, cursorPosY;

View File

@ -42,15 +42,20 @@ static DWORD getWindowStyle(const _GLFWwindow* window)
{ {
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
if (window->decorated && !window->monitor) if (window->monitor)
{
style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
if (window->resizable)
style |= WS_MAXIMIZEBOX | WS_SIZEBOX;
}
else
style |= WS_POPUP; 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; return style;
} }
@ -61,8 +66,8 @@ static DWORD getWindowExStyle(const _GLFWwindow* window)
{ {
DWORD style = WS_EX_APPWINDOW; DWORD style = WS_EX_APPWINDOW;
if (window->decorated && !window->monitor) if (window->monitor || window->floating)
style |= WS_EX_WINDOWEDGE; style |= WS_EX_TOPMOST;
return style; return style;
} }
@ -190,8 +195,7 @@ static void getFullWindowSize(DWORD style, DWORD exStyle,
static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area) static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
{ {
int xoff, yoff; int xoff, yoff;
const float ratio = (float) window->win32.numer / const float ratio = (float) window->numer / (float) window->denom;
(float) window->win32.denom;
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
0, 0, &xoff, &yoff); 0, 0, &xoff, &yoff);
@ -342,7 +346,8 @@ static GLFWbool acquireMonitor(_GLFWwindow* window)
_glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
SetWindowPos(window->win32.handle, HWND_TOPMOST, 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); _glfwInputMonitorWindowChange(window->monitor, window);
return status; return status;
@ -639,8 +644,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_SIZING: case WM_SIZING:
{ {
if (window->win32.numer == GLFW_DONT_CARE || if (window->numer == GLFW_DONT_CARE ||
window->win32.denom == GLFW_DONT_CARE) window->denom == GLFW_DONT_CARE)
{ {
break; break;
} }
@ -654,21 +659,24 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
int xoff, yoff; int xoff, yoff;
MINMAXINFO* mmi = (MINMAXINFO*) lParam; MINMAXINFO* mmi = (MINMAXINFO*) lParam;
if (window->monitor)
break;
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
0, 0, &xoff, &yoff); 0, 0, &xoff, &yoff);
if (window->win32.minwidth != GLFW_DONT_CARE && if (window->minwidth != GLFW_DONT_CARE &&
window->win32.minheight != GLFW_DONT_CARE) window->minheight != GLFW_DONT_CARE)
{ {
mmi->ptMinTrackSize.x = window->win32.minwidth + xoff; mmi->ptMinTrackSize.x = window->minwidth + xoff;
mmi->ptMinTrackSize.y = window->win32.minheight + yoff; mmi->ptMinTrackSize.y = window->minheight + yoff;
} }
if (window->win32.maxwidth != GLFW_DONT_CARE && if (window->maxwidth != GLFW_DONT_CARE &&
window->win32.maxheight != GLFW_DONT_CARE) window->maxheight != GLFW_DONT_CARE)
{ {
mmi->ptMaxTrackSize.x = window->win32.maxwidth + xoff; mmi->ptMaxTrackSize.x = window->maxwidth + xoff;
mmi->ptMaxTrackSize.y = window->win32.maxheight + yoff; mmi->ptMaxTrackSize.y = window->maxheight + yoff;
} }
return 0; return 0;
@ -827,23 +835,8 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig)
WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); 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); 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; return GLFW_TRUE;
} }
@ -976,6 +969,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (window->monitor) if (window->monitor)
{ {
_glfwPlatformShowWindow(window); _glfwPlatformShowWindow(window);
_glfwPlatformFocusWindow(window);
if (!acquireMonitor(window)) if (!acquireMonitor(window))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1093,15 +1087,17 @@ void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height) void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{ {
if (window->monitor) if (window->monitor)
acquireMonitor(window); {
if (window->monitor->window == window)
acquireMonitor(window);
}
else else
{ {
int fullWidth, fullHeight; RECT rect = { 0, 0, width, height };
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window), AdjustWindowRectEx(&rect, getWindowStyle(window),
width, height, &fullWidth, &fullHeight); FALSE, getWindowExStyle(window));
SetWindowPos(window->win32.handle, HWND_TOP, 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); SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
} }
} }
@ -1112,11 +1108,6 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
{ {
RECT area; 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) && if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) &&
(maxwidth == GLFW_DONT_CARE || maxheight == 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; RECT area;
window->win32.numer = numer;
window->win32.denom = denom;
if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE) if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
return; return;
@ -1207,6 +1195,92 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
SetFocus(window->win32.handle); 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) int _glfwPlatformWindowFocused(_GLFWwindow* window)
{ {
return window->win32.handle == GetActiveWindow(); return window->win32.handle == GetActiveWindow();

View File

@ -110,6 +110,11 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window)
window->callbacks.close((GLFWwindow*) window); window->callbacks.close((GLFWwindow*) window);
} }
void _glfwInputWindowMonitorChange(_GLFWwindow* window, _GLFWmonitor* monitor)
{
window->monitor = monitor;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW public API ////// ////// 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)) if (!_glfwIsValidContextConfig(&ctxconfig))
return NULL; return NULL;
@ -182,6 +180,13 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
window->floating = wndconfig.floating; window->floating = wndconfig.floating;
window->cursorMode = GLFW_CURSOR_NORMAL; 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 // Save the currently current context so it can be restored later
previous = _glfwPlatformGetCurrentContext(); previous = _glfwPlatformGetCurrentContext();
@ -510,11 +515,8 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* handle, int width, int height)
_GLFW_REQUIRE_INIT(); _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); _glfwPlatformSetWindowSize(window, width, height);
} }
@ -528,6 +530,11 @@ GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* handle,
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
window->minwidth = minwidth;
window->minheight = minheight;
window->maxwidth = maxwidth;
window->maxheight = maxheight;
if (window->monitor || !window->resizable) if (window->monitor || !window->resizable)
return; return;
@ -543,6 +550,9 @@ GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* handle, int numer, int denom)
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
window->numer = numer;
window->denom = denom;
if (window->monitor || !window->resizable) if (window->monitor || !window->resizable)
return; return;
@ -709,6 +719,27 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* handle)
return (GLFWmonitor*) window->monitor; 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) GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* handle, void* pointer)
{ {
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;

View File

@ -489,6 +489,16 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
fprintf(stderr, "_glfwPlatformFocusWindow not implemented yet\n"); 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) int _glfwPlatformWindowFocused(_GLFWwindow* window)
{ {
// TODO // TODO

View File

@ -199,6 +199,145 @@ static void sendEventToWM(_GLFWwindow* window, Atom type,
&event); &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 // Splits and translates a text/uri-list into separate file paths
// NOTE: This function destroys the provided string // NOTE: This function destroys the provided string
// //
@ -300,84 +439,57 @@ static GLFWbool createWindow(_GLFWwindow* window,
(XPointer) 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 unsigned long flags;
// Setting the override-redirect attribute on a window makes the unsigned long functions;
// window manager ignore the window completely (ICCCM, section 4) unsigned long decorations;
// The good thing is that this makes undecorated full screen windows long input_mode;
// easy to do; the bad thing is that we have to do everything unsigned long status;
// manually and some things (like iconify/restore) won't work at } hints;
// all, as those are tasks usually performed by the window manager
XSetWindowAttributes attributes; hints.flags = 2; // Set decorations
attributes.override_redirect = True; hints.decorations = 0; // No decorations
XChangeWindowAttributes(_glfw.x11.display,
window->x11.handle,
CWOverrideRedirect,
&attributes);
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 if (wndconfig->maximized && !window->monitor)
hints.decorations = 0; // No decorations {
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, XChangeProperty(_glfw.x11.display, window->x11.handle,
_glfw.x11.MOTIF_WM_HINTS, _glfw.x11.NET_WM_STATE, XA_ATOM, 32,
_glfw.x11.MOTIF_WM_HINTS, 32, PropModeReplace, (unsigned char*) &states, 2);
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);
}
} }
} }
// Declare the WM protocols supported by GLFW // Declare the WM protocols supported by GLFW
{ {
int count = 0; int count = 0;
@ -436,27 +548,7 @@ static GLFWbool createWindow(_GLFWwindow* window,
XFree(hints); XFree(hints);
} }
// Set ICCCM WM_NORMAL_HINTS property (even if no parts are set) updateNormalHints(window);
{
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);
}
// Set ICCCM WM_CLASS property // Set ICCCM WM_CLASS property
// HACK: Until a mechanism for specifying the application name is added, the // HACK: Until a mechanism for specifying the application name is added, the
@ -731,24 +823,17 @@ static GLFWbool acquireMonitor(_GLFWwindow* window)
DefaultExposures); DefaultExposures);
} }
_glfw.x11.saver.count++; if (!window->monitor->window)
_glfw.x11.saver.count++;
status = _glfwSetVideoModeX11(window->monitor, &window->videoMode); status = _glfwSetVideoModeX11(window->monitor, &window->videoMode);
if (_glfw.x11.NET_WM_BYPASS_COMPOSITOR) if (window->x11.overrideRedirect)
{
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
{ {
int xpos, ypos; int xpos, ypos;
GLFWvidmode mode; GLFWvidmode mode;
// Manually position the window over its monitor
_glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
_glfwPlatformGetVideoMode(window->monitor, &mode); _glfwPlatformGetVideoMode(window->monitor, &mode);
@ -756,31 +841,6 @@ static GLFWbool acquireMonitor(_GLFWwindow* window)
xpos, ypos, mode.width, mode.height); 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); _glfwInputMonitorWindowChange(window->monitor, window);
return status; return status;
} }
@ -1124,9 +1184,6 @@ static void processEvent(XEvent *event)
case ConfigureNotify: case ConfigureNotify:
{ {
if (!window->x11.overrideRedirect && !event->xany.send_event)
return;
if (event->xconfigure.width != window->x11.width || if (event->xconfigure.width != window->x11.width ||
event->xconfigure.height != window->x11.height) event->xconfigure.height != window->x11.height)
{ {
@ -1145,12 +1202,15 @@ static void processEvent(XEvent *event)
if (event->xconfigure.x != window->x11.xpos || if (event->xconfigure.x != window->x11.xpos ||
event->xconfigure.y != window->x11.ypos) event->xconfigure.y != window->x11.ypos)
{ {
_glfwInputWindowPos(window, if (window->x11.overrideRedirect || event->xany.send_event)
event->xconfigure.x, {
event->xconfigure.y); _glfwInputWindowPos(window,
event->xconfigure.x,
event->xconfigure.y);
window->x11.xpos = event->xconfigure.x; window->x11.xpos = event->xconfigure.x;
window->x11.ypos = event->xconfigure.y; window->x11.ypos = event->xconfigure.y;
}
} }
return; return;
@ -1459,6 +1519,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (window->monitor) if (window->monitor)
{ {
_glfwPlatformShowWindow(window); _glfwPlatformShowWindow(window);
updateWindowMode(window);
if (!acquireMonitor(window)) if (!acquireMonitor(window))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1654,31 +1715,13 @@ void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
{ {
if (window->monitor) if (window->monitor)
{ {
_glfwSetVideoModeX11(window->monitor, &window->videoMode); if (window->monitor->window == window)
acquireMonitor(window);
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);
}
} }
else else
{ {
if (!window->resizable) if (!window->resizable)
{ updateNormalHints(window);
// 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);
}
XResizeWindow(_glfw.x11.display, window->x11.handle, width, height); XResizeWindow(_glfw.x11.display, window->x11.handle, width, height);
} }
@ -1690,55 +1733,14 @@ void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
int minwidth, int minheight, int minwidth, int minheight,
int maxwidth, int maxheight) int maxwidth, int maxheight)
{ {
long supplied; updateNormalHints(window);
XSizeHints* hints = XAllocSizeHints(); XFlush(_glfw.x11.display);
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);
} }
void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom) void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
{ {
long supplied; updateNormalHints(window);
XSizeHints* hints = XAllocSizeHints(); XFlush(_glfw.x11.display);
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);
} }
void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height) void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
@ -1907,6 +1909,48 @@ void _glfwPlatformFocusWindow(_GLFWwindow* window)
XFlush(_glfw.x11.display); 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) int _glfwPlatformWindowFocused(_GLFWwindow* window)
{ {
Window focused; Window focused;

View File

@ -36,6 +36,8 @@
#include "getopt.h" #include "getopt.h"
static int windowed_xpos, windowed_ypos, windowed_width, windowed_height;
static void usage(void) static void usage(void)
{ {
printf("Usage: iconify [-h] [-f [-a] [-n]]\n"); 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: case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, GLFW_TRUE); glfwSetWindowShouldClose(window, GLFW_TRUE);
break; 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;
}
} }
} }