Added support for _NET_WM_FULLSCREEN_MONITORS.

This allows EWMH full screen windows to correctly cover monitors that
overlap other monitors, such as an Oculus Rift mapped onto a section of
a larger monitor.

Fixes #175.
This commit is contained in:
Camilla Berglund 2014-09-22 12:49:03 +02:00
parent 2488c67798
commit 4918514eaf
5 changed files with 75 additions and 1 deletions

View File

@ -222,6 +222,15 @@ if (_GLFW_X11)
list(APPEND glfw_LIBRARIES "${X11_Xrandr_LIB}") list(APPEND glfw_LIBRARIES "${X11_Xrandr_LIB}")
set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xrandr") set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xrandr")
# Check for Xinerama (legacy multi-monitor support)
if (NOT X11_Xinerama_FOUND)
message(FATAL_ERROR "The Xinerama library and headers were not found")
endif()
list(APPEND glfw_INCLUDE_DIRS "${X11_Xinerama_INCLUDE_PATH}")
list(APPEND glfw_LIBRARIES "${X11_Xinerama_LIB}")
set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} xinerama")
# Check for XInput (high-resolution cursor motion) # Check for XInput (high-resolution cursor motion)
if (NOT X11_Xinput_FOUND) if (NOT X11_Xinput_FOUND)
message(FATAL_ERROR "The XInput library and headers were not found") message(FATAL_ERROR "The XInput library and headers were not found")

View File

@ -447,6 +447,8 @@ static void detectEWMH(void)
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE");
_glfw.x11.NET_WM_STATE_FULLSCREEN = _glfw.x11.NET_WM_STATE_FULLSCREEN =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN"); getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_FULLSCREEN");
_glfw.x11.NET_WM_FULLSCREEN_MONITORS =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_FULLSCREEN_MONITORS");
_glfw.x11.NET_WM_NAME = _glfw.x11.NET_WM_NAME =
getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME"); getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME");
_glfw.x11.NET_WM_ICON_NAME = _glfw.x11.NET_WM_ICON_NAME =
@ -533,6 +535,14 @@ static GLboolean initExtensions(void)
XRRFreeScreenResources(sr); XRRFreeScreenResources(sr);
} }
if (XineramaQueryExtension(_glfw.x11.display,
&_glfw.x11.xinerama.versionMajor,
&_glfw.x11.xinerama.versionMinor))
{
if (XineramaIsActive(_glfw.x11.display))
_glfw.x11.xinerama.available = GL_TRUE;
}
if (XQueryExtension(_glfw.x11.display, if (XQueryExtension(_glfw.x11.display,
"XInputExtension", "XInputExtension",
&_glfw.x11.xi.majorOpcode, &_glfw.x11.xi.majorOpcode,

View File

@ -200,18 +200,23 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor)
_GLFWmonitor** _glfwPlatformGetMonitors(int* count) _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
{ {
int i, j, size = 0, found = 0; int i, j, k, size = 0, found = 0;
_GLFWmonitor** monitors = NULL; _GLFWmonitor** monitors = NULL;
*count = 0; *count = 0;
if (_glfw.x11.randr.available) if (_glfw.x11.randr.available)
{ {
int screenCount = 0;
XineramaScreenInfo* screens = NULL;
XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display, XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display,
_glfw.x11.root); _glfw.x11.root);
RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, RROutput primary = XRRGetOutputPrimary(_glfw.x11.display,
_glfw.x11.root); _glfw.x11.root);
if (_glfw.x11.xinerama.available)
screens = XineramaQueryScreens(_glfw.x11.display, &screenCount);
for (i = 0; i < sr->ncrtc; i++) for (i = 0; i < sr->ncrtc; i++)
{ {
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display,
@ -240,6 +245,18 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
monitors[found]->x11.output = ci->outputs[j]; monitors[found]->x11.output = ci->outputs[j];
monitors[found]->x11.crtc = oi->crtc; monitors[found]->x11.crtc = oi->crtc;
for (k = 0; k < screenCount; k++)
{
if (screens[k].x_org == ci->x &&
screens[k].y_org == ci->y &&
screens[k].width == ci->width &&
screens[k].height == ci->height)
{
monitors[found]->x11.index = k;
break;
}
}
XRRFreeOutputInfo(oi); XRRFreeOutputInfo(oi);
if (ci->outputs[j] == primary) if (ci->outputs[j] == primary)
@ -253,6 +270,9 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count)
XRRFreeScreenResources(sr); XRRFreeScreenResources(sr);
if (screens)
XFree(screens);
if (found == 0) if (found == 0)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,

View File

@ -48,6 +48,9 @@
// The Xkb extension provides improved keyboard support // The Xkb extension provides improved keyboard support
#include <X11/XKBlib.h> #include <X11/XKBlib.h>
// The Xinerama extension provides legacy monitor indices
#include <X11/extensions/Xinerama.h>
#include "posix_tls.h" #include "posix_tls.h"
#if defined(_GLFW_GLX) #if defined(_GLFW_GLX)
@ -130,6 +133,7 @@ typedef struct _GLFWlibraryX11
Atom NET_WM_STATE_ABOVE; Atom NET_WM_STATE_ABOVE;
Atom NET_WM_STATE_FULLSCREEN; Atom NET_WM_STATE_FULLSCREEN;
Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_WM_BYPASS_COMPOSITOR;
Atom NET_WM_FULLSCREEN_MONITORS;
Atom NET_ACTIVE_WINDOW; Atom NET_ACTIVE_WINDOW;
Atom NET_FRAME_EXTENTS; Atom NET_FRAME_EXTENTS;
Atom NET_REQUEST_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS;
@ -205,6 +209,12 @@ typedef struct _GLFWlibraryX11
Window source; Window source;
} xdnd; } xdnd;
struct {
GLboolean available;
int versionMajor;
int versionMinor;
} xinerama;
} _GLFWlibraryX11; } _GLFWlibraryX11;
@ -216,6 +226,10 @@ typedef struct _GLFWmonitorX11
RRCrtc crtc; RRCrtc crtc;
RRMode oldMode; RRMode oldMode;
// Index of corresponding Xinerama screen,
// for EWMH full screen window placement
int index;
} _GLFWmonitorX11; } _GLFWmonitorX11;

View File

@ -715,6 +715,27 @@ static void enterFullscreenMode(_GLFWwindow* window)
PropModeReplace, (unsigned char*) &value, 1); PropModeReplace, (unsigned char*) &value, 1);
} }
if (_glfw.x11.xinerama.available && _glfw.x11.NET_WM_FULLSCREEN_MONITORS)
{
XEvent event;
memset(&event, 0, sizeof(event));
event.type = ClientMessage;
event.xclient.window = window->x11.handle;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = _glfw.x11.NET_WM_FULLSCREEN_MONITORS;
event.xclient.data.l[0] = window->monitor->x11.index;
event.xclient.data.l[1] = window->monitor->x11.index;
event.xclient.data.l[2] = window->monitor->x11.index;
event.xclient.data.l[3] = window->monitor->x11.index;
XSendEvent(_glfw.x11.display,
_glfw.x11.root,
False,
SubstructureNotifyMask | SubstructureRedirectMask,
&event);
}
if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN) if (_glfw.x11.NET_WM_STATE && _glfw.x11.NET_WM_STATE_FULLSCREEN)
{ {
int x, y; int x, y;