Moved EWMH logic to library init.

This commit is contained in:
Camilla Berglund 2012-04-05 17:29:08 +02:00
parent 3184e1a70a
commit 76615bf237
3 changed files with 187 additions and 187 deletions

View File

@ -33,6 +33,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.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 // Initialize X11 display and look for supported X11 extensions
//======================================================================== //========================================================================
@ -580,6 +727,8 @@ int _glfwPlatformInit(void)
initGammaRamp(); initGammaRamp();
initEWMH();
_glfwLibrary.X11.cursor = createNULLCursor(); _glfwLibrary.X11.cursor = createNULLCursor();
// Try to load libGL.so if necessary // Try to load libGL.so if necessary

View File

@ -133,16 +133,8 @@ typedef struct _GLFWwindowX11
// Platform specific window resources // Platform specific window resources
Colormap colormap; // Window colormap Colormap colormap; // Window colormap
Window handle; // Window handle 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 // Various platform specific internal variables
GLboolean hasEWMH; // True if window manager supports EWMH
GLboolean overrideRedirect; // True if window is OverrideRedirect GLboolean overrideRedirect; // True if window is OverrideRedirect
GLboolean keyboardGrabbed; // True if keyboard is currently grabbed GLboolean keyboardGrabbed; // True if keyboard is currently grabbed
GLboolean cursorGrabbed; // True if cursor is currently grabbed GLboolean cursorGrabbed; // True if cursor is currently grabbed
@ -163,6 +155,17 @@ typedef struct _GLFWlibraryX11
Window root; Window root;
Cursor cursor; // Invisible cursor for hidden cursor 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 // Server-side GLX version
int glxMajor, glxMinor; int glxMajor, glxMinor;

View File

@ -30,7 +30,6 @@
#include "internal.h" #include "internal.h"
#include <limits.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.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 // 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 if (window->mode == GLFW_FULLSCREEN && !_glfwLibrary.X11.hasEWMH)
window->X11.hasEWMH = hasEWMH(window);
if (window->mode == GLFW_FULLSCREEN && !window->X11.hasEWMH)
{ {
// This is the butcher's way of removing window decorations // This is the butcher's way of removing window decorations
// Setting the override-redirect attribute on a window makes the window // 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 // Find or create the protocol atom for window close notifications
window->X11.wmDeleteWindow = XInternAtom(_glfwLibrary.X11.display, _glfwLibrary.X11.wmDeleteWindow = XInternAtom(_glfwLibrary.X11.display,
"WM_DELETE_WINDOW", "WM_DELETE_WINDOW",
False); False);
// Declare the WM protocols we support // Declare the WM protocols we support
{ {
@ -756,14 +604,14 @@ static GLboolean createWindow(_GLFWwindow* window,
// The WM_DELETE_WINDOW ICCCM protocol // The WM_DELETE_WINDOW ICCCM protocol
// Basic window close notification protocol // Basic window close notification protocol
if (window->X11.wmDeleteWindow != None) if (_glfwLibrary.X11.wmDeleteWindow != None)
protocols[count++] = window->X11.wmDeleteWindow; protocols[count++] = _glfwLibrary.X11.wmDeleteWindow;
// The _NET_WM_PING EWMH protocol // The _NET_WM_PING EWMH protocol
// Tells the WM to ping our window and flag us as unresponsive if we // Tells the WM to ping our window and flag us as unresponsive if we
// don't reply within a few seconds // don't reply within a few seconds
if (window->X11.wmPing != None) if (_glfwLibrary.X11.wmPing != None)
protocols[count++] = window->X11.wmPing; protocols[count++] = _glfwLibrary.X11.wmPing;
if (count > 0) if (count > 0)
{ {
@ -911,11 +759,11 @@ static void enterFullscreenMode(_GLFWwindow* window)
_glfwSetVideoMode(&window->width, &window->height, _glfwSetVideoMode(&window->width, &window->height,
&window->refreshRate); &window->refreshRate);
if (window->X11.hasEWMH && if (_glfwLibrary.X11.hasEWMH &&
window->X11.wmState != None && _glfwLibrary.X11.wmState != None &&
window->X11.wmStateFullscreen != 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 // Ask the window manager to raise and focus the GLFW window
// Only focused windows with the _NET_WM_STATE_FULLSCREEN state end // Only focused windows with the _NET_WM_STATE_FULLSCREEN state end
@ -927,7 +775,7 @@ static void enterFullscreenMode(_GLFWwindow* window)
event.type = ClientMessage; event.type = ClientMessage;
event.xclient.window = window->X11.handle; event.xclient.window = window->X11.handle;
event.xclient.format = 32; // Data is 32-bit longs 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[0] = 1; // Sender is a normal application
event.xclient.data.l[1] = 0; // We don't really know the timestamp 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.type = ClientMessage;
event.xclient.window = window->X11.handle; event.xclient.window = window->X11.handle;
event.xclient.format = 32; // Data is 32-bit longs 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[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[2] = 0; // No secondary property
event.xclient.data.l[3] = 1; // Sender is a normal application 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; _glfwLibrary.X11.saver.changed = GL_FALSE;
} }
if (window->X11.hasEWMH && if (_glfwLibrary.X11.hasEWMH &&
window->X11.wmState != None && _glfwLibrary.X11.wmState != None &&
window->X11.wmStateFullscreen != None) _glfwLibrary.X11.wmStateFullscreen != None)
{ {
// Ask the window manager to make the GLFW window a normal window // Ask the window manager to make the GLFW window a normal window
// Normal windows usually have frames and other decorations // Normal windows usually have frames and other decorations
@ -1016,9 +864,9 @@ static void leaveFullscreenMode(_GLFWwindow* window)
event.type = ClientMessage; event.type = ClientMessage;
event.xclient.window = window->X11.handle; event.xclient.window = window->X11.handle;
event.xclient.format = 32; // Data is 32-bit longs 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[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[2] = 0; // No secondary property
event.xclient.data.l[3] = 1; // Sender is a normal application event.xclient.data.l[3] = 1; // Sender is a normal application
@ -1291,15 +1139,15 @@ static void processSingleEvent(void)
return; 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 window manager was asked to close the window, for example by
// the user pressing a 'close' window decoration button // the user pressing a 'close' window decoration button
window->closeRequested = GL_TRUE; window->closeRequested = GL_TRUE;
} }
else if (window->X11.wmPing != None && else if (_glfwLibrary.X11.wmPing != None &&
(Atom) event.xclient.data.l[0] == window->X11.wmPing) (Atom) event.xclient.data.l[0] == _glfwLibrary.X11.wmPing)
{ {
// The window manager is pinging us to make sure we are still // The window manager is pinging us to make sure we are still
// responding to events // responding to events
@ -1567,18 +1415,18 @@ void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
NULL, NULL, NULL); NULL, NULL, NULL);
#endif #endif
if (window->X11.wmName != None) if (_glfwLibrary.X11.wmName != None)
{ {
XChangeProperty(_glfwLibrary.X11.display, window->X11.handle, XChangeProperty(_glfwLibrary.X11.display, window->X11.handle,
window->X11.wmName, type, 8, _glfwLibrary.X11.wmName, type, 8,
PropModeReplace, PropModeReplace,
(unsigned char*) title, strlen(title)); (unsigned char*) title, strlen(title));
} }
if (window->X11.wmIconName != None) if (_glfwLibrary.X11.wmIconName != None)
{ {
XChangeProperty(_glfwLibrary.X11.display, window->X11.handle, XChangeProperty(_glfwLibrary.X11.display, window->X11.handle,
window->X11.wmIconName, type, 8, _glfwLibrary.X11.wmIconName, type, 8,
PropModeReplace, PropModeReplace,
(unsigned char*) title, strlen(title)); (unsigned char*) title, strlen(title));
} }