mirror of
https://github.com/glfw/glfw.git
synced 2024-11-10 09:01:46 +00:00
Moved EWMH logic to library init.
This commit is contained in:
parent
3184e1a70a
commit
76615bf237
149
src/x11_init.c
149
src/x11_init.c
@ -33,6 +33,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
//========================================================================
|
||||
@ -369,6 +370,152 @@ static void updateKeyCodeLUT(void)
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Retrieve a single window property of the specified type
|
||||
// Inspired by fghGetWindowProperty from freeglut
|
||||
//========================================================================
|
||||
|
||||
static unsigned long getWindowProperty(Window window,
|
||||
Atom property,
|
||||
Atom type,
|
||||
unsigned char** value)
|
||||
{
|
||||
Atom actualType;
|
||||
int actualFormat;
|
||||
unsigned long itemCount, bytesAfter;
|
||||
|
||||
XGetWindowProperty(_glfwLibrary.X11.display,
|
||||
window,
|
||||
property,
|
||||
0,
|
||||
LONG_MAX,
|
||||
False,
|
||||
type,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&itemCount,
|
||||
&bytesAfter,
|
||||
value);
|
||||
|
||||
if (actualType != type)
|
||||
return 0;
|
||||
|
||||
return itemCount;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Check whether the specified atom is supported
|
||||
//========================================================================
|
||||
|
||||
static Atom getSupportedAtom(Atom* supportedAtoms,
|
||||
unsigned long atomCount,
|
||||
const char* atomName)
|
||||
{
|
||||
Atom atom = XInternAtom(_glfwLibrary.X11.display, atomName, True);
|
||||
if (atom != None)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < atomCount; i++)
|
||||
{
|
||||
if (supportedAtoms[i] == atom)
|
||||
return atom;
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Check whether the running window manager is EWMH-compliant
|
||||
//========================================================================
|
||||
|
||||
static void initEWMH(void)
|
||||
{
|
||||
Window* windowFromRoot = NULL;
|
||||
Window* windowFromChild = NULL;
|
||||
|
||||
// First we need a couple of atoms, which should already be there
|
||||
Atom supportingWmCheck =
|
||||
XInternAtom(_glfwLibrary.X11.display, "_NET_SUPPORTING_WM_CHECK", True);
|
||||
Atom wmSupported =
|
||||
XInternAtom(_glfwLibrary.X11.display, "_NET_SUPPORTED", True);
|
||||
if (supportingWmCheck == None || wmSupported == None)
|
||||
return;
|
||||
|
||||
// Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
|
||||
if (getWindowProperty(_glfwLibrary.X11.root,
|
||||
supportingWmCheck,
|
||||
XA_WINDOW,
|
||||
(unsigned char**) &windowFromRoot) != 1)
|
||||
{
|
||||
XFree(windowFromRoot);
|
||||
return;
|
||||
}
|
||||
|
||||
// It should be the ID of a child window (of the root)
|
||||
// Then we look for the same property on the child window
|
||||
if (getWindowProperty(*windowFromRoot,
|
||||
supportingWmCheck,
|
||||
XA_WINDOW,
|
||||
(unsigned char**) &windowFromChild) != 1)
|
||||
{
|
||||
XFree(windowFromRoot);
|
||||
XFree(windowFromChild);
|
||||
return;
|
||||
}
|
||||
|
||||
// It should be the ID of that same child window
|
||||
if (*windowFromRoot != *windowFromChild)
|
||||
{
|
||||
XFree(windowFromRoot);
|
||||
XFree(windowFromChild);
|
||||
return;
|
||||
}
|
||||
|
||||
XFree(windowFromRoot);
|
||||
XFree(windowFromChild);
|
||||
|
||||
// We are now fairly sure that an EWMH-compliant window manager is running
|
||||
|
||||
Atom* supportedAtoms;
|
||||
unsigned long atomCount;
|
||||
|
||||
// Now we need to check the _NET_SUPPORTED property of the root window
|
||||
// It should be a list of supported WM protocol and state atoms
|
||||
atomCount = getWindowProperty(_glfwLibrary.X11.root,
|
||||
wmSupported,
|
||||
XA_ATOM,
|
||||
(unsigned char**) &supportedAtoms);
|
||||
|
||||
// See which of the atoms we support that are supported by the WM
|
||||
|
||||
_glfwLibrary.X11.wmState =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
|
||||
|
||||
_glfwLibrary.X11.wmStateFullscreen =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
|
||||
|
||||
_glfwLibrary.X11.wmName =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME");
|
||||
|
||||
_glfwLibrary.X11.wmIconName =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON_NAME");
|
||||
|
||||
_glfwLibrary.X11.wmPing =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PING");
|
||||
|
||||
_glfwLibrary.X11.wmActiveWindow =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
|
||||
|
||||
XFree(supportedAtoms);
|
||||
|
||||
_glfwLibrary.X11.hasEWMH = GL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Initialize X11 display and look for supported X11 extensions
|
||||
//========================================================================
|
||||
@ -580,6 +727,8 @@ int _glfwPlatformInit(void)
|
||||
|
||||
initGammaRamp();
|
||||
|
||||
initEWMH();
|
||||
|
||||
_glfwLibrary.X11.cursor = createNULLCursor();
|
||||
|
||||
// Try to load libGL.so if necessary
|
||||
|
@ -133,16 +133,8 @@ typedef struct _GLFWwindowX11
|
||||
// Platform specific window resources
|
||||
Colormap colormap; // Window colormap
|
||||
Window handle; // Window handle
|
||||
Atom wmDeleteWindow; // WM_DELETE_WINDOW atom
|
||||
Atom wmName; // _NET_WM_NAME atom
|
||||
Atom wmIconName; // _NET_WM_ICON_NAME atom
|
||||
Atom wmPing; // _NET_WM_PING atom
|
||||
Atom wmState; // _NET_WM_STATE atom
|
||||
Atom wmStateFullscreen; // _NET_WM_STATE_FULLSCREEN atom
|
||||
Atom wmActiveWindow; // _NET_ACTIVE_WINDOW atom
|
||||
|
||||
// Various platform specific internal variables
|
||||
GLboolean hasEWMH; // True if window manager supports EWMH
|
||||
GLboolean overrideRedirect; // True if window is OverrideRedirect
|
||||
GLboolean keyboardGrabbed; // True if keyboard is currently grabbed
|
||||
GLboolean cursorGrabbed; // True if cursor is currently grabbed
|
||||
@ -163,6 +155,17 @@ typedef struct _GLFWlibraryX11
|
||||
Window root;
|
||||
Cursor cursor; // Invisible cursor for hidden cursor
|
||||
|
||||
Atom wmDeleteWindow; // WM_DELETE_WINDOW atom
|
||||
Atom wmName; // _NET_WM_NAME atom
|
||||
Atom wmIconName; // _NET_WM_ICON_NAME atom
|
||||
Atom wmPing; // _NET_WM_PING atom
|
||||
Atom wmState; // _NET_WM_STATE atom
|
||||
Atom wmStateFullscreen; // _NET_WM_STATE_FULLSCREEN atom
|
||||
Atom wmActiveWindow; // _NET_ACTIVE_WINDOW atom
|
||||
|
||||
// True if window manager supports EWMH
|
||||
GLboolean hasEWMH;
|
||||
|
||||
// Server-side GLX version
|
||||
int glxMajor, glxMinor;
|
||||
|
||||
|
206
src/x11_window.c
206
src/x11_window.c
@ -30,7 +30,6 @@
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -65,154 +64,6 @@ static Bool isMapNotify(Display* d, XEvent* e, char* arg)
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Retrieve a single window property of the specified type
|
||||
// Inspired by fghGetWindowProperty from freeglut
|
||||
//========================================================================
|
||||
|
||||
static unsigned long getWindowProperty(Window window,
|
||||
Atom property,
|
||||
Atom type,
|
||||
unsigned char** value)
|
||||
{
|
||||
Atom actualType;
|
||||
int actualFormat;
|
||||
unsigned long itemCount, bytesAfter;
|
||||
|
||||
XGetWindowProperty(_glfwLibrary.X11.display,
|
||||
window,
|
||||
property,
|
||||
0,
|
||||
LONG_MAX,
|
||||
False,
|
||||
type,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&itemCount,
|
||||
&bytesAfter,
|
||||
value);
|
||||
|
||||
if (actualType != type)
|
||||
return 0;
|
||||
|
||||
return itemCount;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Check whether the specified atom is supported
|
||||
//========================================================================
|
||||
|
||||
static Atom getSupportedAtom(Atom* supportedAtoms,
|
||||
unsigned long atomCount,
|
||||
const char* atomName)
|
||||
{
|
||||
Atom atom = XInternAtom(_glfwLibrary.X11.display, atomName, True);
|
||||
if (atom != None)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < atomCount; i++)
|
||||
{
|
||||
if (supportedAtoms[i] == atom)
|
||||
return atom;
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Check whether the running window manager is EWMH-compliant
|
||||
//========================================================================
|
||||
|
||||
static GLboolean hasEWMH(_GLFWwindow* window)
|
||||
{
|
||||
Window* windowFromRoot = NULL;
|
||||
Window* windowFromChild = NULL;
|
||||
|
||||
// Hey kids; let's see if the window manager supports EWMH!
|
||||
|
||||
// First we need a couple of atoms, which should already be there
|
||||
Atom supportingWmCheck =
|
||||
XInternAtom(_glfwLibrary.X11.display, "_NET_SUPPORTING_WM_CHECK", True);
|
||||
Atom wmSupported =
|
||||
XInternAtom(_glfwLibrary.X11.display, "_NET_SUPPORTED", True);
|
||||
if (supportingWmCheck == None || wmSupported == None)
|
||||
return GL_FALSE;
|
||||
|
||||
// Then we look for the _NET_SUPPORTING_WM_CHECK property of the root window
|
||||
if (getWindowProperty(_glfwLibrary.X11.root,
|
||||
supportingWmCheck,
|
||||
XA_WINDOW,
|
||||
(unsigned char**) &windowFromRoot) != 1)
|
||||
{
|
||||
XFree(windowFromRoot);
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
// It should be the ID of a child window (of the root)
|
||||
// Then we look for the same property on the child window
|
||||
if (getWindowProperty(*windowFromRoot,
|
||||
supportingWmCheck,
|
||||
XA_WINDOW,
|
||||
(unsigned char**) &windowFromChild) != 1)
|
||||
{
|
||||
XFree(windowFromRoot);
|
||||
XFree(windowFromChild);
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
// It should be the ID of that same child window
|
||||
if (*windowFromRoot != *windowFromChild)
|
||||
{
|
||||
XFree(windowFromRoot);
|
||||
XFree(windowFromChild);
|
||||
return GL_FALSE;
|
||||
}
|
||||
|
||||
XFree(windowFromRoot);
|
||||
XFree(windowFromChild);
|
||||
|
||||
// We are now fairly sure that an EWMH-compliant window manager is running
|
||||
|
||||
Atom* supportedAtoms;
|
||||
unsigned long atomCount;
|
||||
|
||||
// Now we need to check the _NET_SUPPORTED property of the root window
|
||||
// It should be a list of supported WM protocol and state atoms
|
||||
atomCount = getWindowProperty(_glfwLibrary.X11.root,
|
||||
wmSupported,
|
||||
XA_ATOM,
|
||||
(unsigned char**) &supportedAtoms);
|
||||
|
||||
// See which of the atoms we support that are supported by the WM
|
||||
|
||||
window->X11.wmState =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
|
||||
|
||||
window->X11.wmStateFullscreen =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
|
||||
|
||||
window->X11.wmName =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME");
|
||||
|
||||
window->X11.wmIconName =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_ICON_NAME");
|
||||
|
||||
window->X11.wmPing =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_PING");
|
||||
|
||||
window->X11.wmActiveWindow =
|
||||
getSupportedAtom(supportedAtoms, atomCount, "_NET_ACTIVE_WINDOW");
|
||||
|
||||
XFree(supportedAtoms);
|
||||
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Translates an X Window key to internal coding
|
||||
//========================================================================
|
||||
@ -721,10 +572,7 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether an EWMH-compliant window manager is running
|
||||
window->X11.hasEWMH = hasEWMH(window);
|
||||
|
||||
if (window->mode == GLFW_FULLSCREEN && !window->X11.hasEWMH)
|
||||
if (window->mode == GLFW_FULLSCREEN && !_glfwLibrary.X11.hasEWMH)
|
||||
{
|
||||
// This is the butcher's way of removing window decorations
|
||||
// Setting the override-redirect attribute on a window makes the window
|
||||
@ -745,9 +593,9 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
}
|
||||
|
||||
// Find or create the protocol atom for window close notifications
|
||||
window->X11.wmDeleteWindow = XInternAtom(_glfwLibrary.X11.display,
|
||||
"WM_DELETE_WINDOW",
|
||||
False);
|
||||
_glfwLibrary.X11.wmDeleteWindow = XInternAtom(_glfwLibrary.X11.display,
|
||||
"WM_DELETE_WINDOW",
|
||||
False);
|
||||
|
||||
// Declare the WM protocols we support
|
||||
{
|
||||
@ -756,14 +604,14 @@ static GLboolean createWindow(_GLFWwindow* window,
|
||||
|
||||
// The WM_DELETE_WINDOW ICCCM protocol
|
||||
// Basic window close notification protocol
|
||||
if (window->X11.wmDeleteWindow != None)
|
||||
protocols[count++] = window->X11.wmDeleteWindow;
|
||||
if (_glfwLibrary.X11.wmDeleteWindow != None)
|
||||
protocols[count++] = _glfwLibrary.X11.wmDeleteWindow;
|
||||
|
||||
// The _NET_WM_PING EWMH protocol
|
||||
// Tells the WM to ping our window and flag us as unresponsive if we
|
||||
// don't reply within a few seconds
|
||||
if (window->X11.wmPing != None)
|
||||
protocols[count++] = window->X11.wmPing;
|
||||
if (_glfwLibrary.X11.wmPing != None)
|
||||
protocols[count++] = _glfwLibrary.X11.wmPing;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
@ -911,11 +759,11 @@ static void enterFullscreenMode(_GLFWwindow* window)
|
||||
_glfwSetVideoMode(&window->width, &window->height,
|
||||
&window->refreshRate);
|
||||
|
||||
if (window->X11.hasEWMH &&
|
||||
window->X11.wmState != None &&
|
||||
window->X11.wmStateFullscreen != None)
|
||||
if (_glfwLibrary.X11.hasEWMH &&
|
||||
_glfwLibrary.X11.wmState != None &&
|
||||
_glfwLibrary.X11.wmStateFullscreen != None)
|
||||
{
|
||||
if (window->X11.wmActiveWindow != None)
|
||||
if (_glfwLibrary.X11.wmActiveWindow != None)
|
||||
{
|
||||
// Ask the window manager to raise and focus the GLFW window
|
||||
// Only focused windows with the _NET_WM_STATE_FULLSCREEN state end
|
||||
@ -927,7 +775,7 @@ static void enterFullscreenMode(_GLFWwindow* window)
|
||||
event.type = ClientMessage;
|
||||
event.xclient.window = window->X11.handle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = window->X11.wmActiveWindow;
|
||||
event.xclient.message_type = _glfwLibrary.X11.wmActiveWindow;
|
||||
event.xclient.data.l[0] = 1; // Sender is a normal application
|
||||
event.xclient.data.l[1] = 0; // We don't really know the timestamp
|
||||
|
||||
@ -948,9 +796,9 @@ static void enterFullscreenMode(_GLFWwindow* window)
|
||||
event.type = ClientMessage;
|
||||
event.xclient.window = window->X11.handle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = window->X11.wmState;
|
||||
event.xclient.message_type = _glfwLibrary.X11.wmState;
|
||||
event.xclient.data.l[0] = _NET_WM_STATE_ADD;
|
||||
event.xclient.data.l[1] = window->X11.wmStateFullscreen;
|
||||
event.xclient.data.l[1] = _glfwLibrary.X11.wmStateFullscreen;
|
||||
event.xclient.data.l[2] = 0; // No secondary property
|
||||
event.xclient.data.l[3] = 1; // Sender is a normal application
|
||||
|
||||
@ -1003,9 +851,9 @@ static void leaveFullscreenMode(_GLFWwindow* window)
|
||||
_glfwLibrary.X11.saver.changed = GL_FALSE;
|
||||
}
|
||||
|
||||
if (window->X11.hasEWMH &&
|
||||
window->X11.wmState != None &&
|
||||
window->X11.wmStateFullscreen != None)
|
||||
if (_glfwLibrary.X11.hasEWMH &&
|
||||
_glfwLibrary.X11.wmState != None &&
|
||||
_glfwLibrary.X11.wmStateFullscreen != None)
|
||||
{
|
||||
// Ask the window manager to make the GLFW window a normal window
|
||||
// Normal windows usually have frames and other decorations
|
||||
@ -1016,9 +864,9 @@ static void leaveFullscreenMode(_GLFWwindow* window)
|
||||
event.type = ClientMessage;
|
||||
event.xclient.window = window->X11.handle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = window->X11.wmState;
|
||||
event.xclient.message_type = _glfwLibrary.X11.wmState;
|
||||
event.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
|
||||
event.xclient.data.l[1] = window->X11.wmStateFullscreen;
|
||||
event.xclient.data.l[1] = _glfwLibrary.X11.wmStateFullscreen;
|
||||
event.xclient.data.l[2] = 0; // No secondary property
|
||||
event.xclient.data.l[3] = 1; // Sender is a normal application
|
||||
|
||||
@ -1291,15 +1139,15 @@ static void processSingleEvent(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Atom) event.xclient.data.l[0] == window->X11.wmDeleteWindow)
|
||||
if ((Atom) event.xclient.data.l[0] == _glfwLibrary.X11.wmDeleteWindow)
|
||||
{
|
||||
// The window manager was asked to close the window, for example by
|
||||
// the user pressing a 'close' window decoration button
|
||||
|
||||
window->closeRequested = GL_TRUE;
|
||||
}
|
||||
else if (window->X11.wmPing != None &&
|
||||
(Atom) event.xclient.data.l[0] == window->X11.wmPing)
|
||||
else if (_glfwLibrary.X11.wmPing != None &&
|
||||
(Atom) event.xclient.data.l[0] == _glfwLibrary.X11.wmPing)
|
||||
{
|
||||
// The window manager is pinging us to make sure we are still
|
||||
// responding to events
|
||||
@ -1567,18 +1415,18 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
|
||||
NULL, NULL, NULL);
|
||||
#endif
|
||||
|
||||
if (window->X11.wmName != None)
|
||||
if (_glfwLibrary.X11.wmName != None)
|
||||
{
|
||||
XChangeProperty(_glfwLibrary.X11.display, window->X11.handle,
|
||||
window->X11.wmName, type, 8,
|
||||
_glfwLibrary.X11.wmName, type, 8,
|
||||
PropModeReplace,
|
||||
(unsigned char*) title, strlen(title));
|
||||
}
|
||||
|
||||
if (window->X11.wmIconName != None)
|
||||
if (_glfwLibrary.X11.wmIconName != None)
|
||||
{
|
||||
XChangeProperty(_glfwLibrary.X11.display, window->X11.handle,
|
||||
window->X11.wmIconName, type, 8,
|
||||
_glfwLibrary.X11.wmIconName, type, 8,
|
||||
PropModeReplace,
|
||||
(unsigned char*) title, strlen(title));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user