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
+126 -19
View File
@@ -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];
+11
View File
@@ -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.
+10
View File
@@ -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,
+5 -1
View File
@@ -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)
-4
View File
@@ -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;
+126 -52
View File
@@ -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();
+43 -12
View File
@@ -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;
+10
View File
@@ -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
+241 -197
View File
@@ -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;