From 4918514eafd620f63916c62c82a5c67636f64848 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 22 Sep 2014 12:49:03 +0200 Subject: [PATCH] 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. --- CMakeLists.txt | 9 +++++++++ src/x11_init.c | 10 ++++++++++ src/x11_monitor.c | 22 +++++++++++++++++++++- src/x11_platform.h | 14 ++++++++++++++ src/x11_window.c | 21 +++++++++++++++++++++ 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc338bc4..f827aa29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,6 +222,15 @@ if (_GLFW_X11) list(APPEND glfw_LIBRARIES "${X11_Xrandr_LIB}") 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) if (NOT X11_Xinput_FOUND) message(FATAL_ERROR "The XInput library and headers were not found") diff --git a/src/x11_init.c b/src/x11_init.c index 028d715d..ea0b6934 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -447,6 +447,8 @@ static void detectEWMH(void) getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE_ABOVE"); _glfw.x11.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 = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_NAME"); _glfw.x11.NET_WM_ICON_NAME = @@ -533,6 +535,14 @@ static GLboolean initExtensions(void) 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, "XInputExtension", &_glfw.x11.xi.majorOpcode, diff --git a/src/x11_monitor.c b/src/x11_monitor.c index 679cafb0..d0bbb434 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -200,18 +200,23 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor) _GLFWmonitor** _glfwPlatformGetMonitors(int* count) { - int i, j, size = 0, found = 0; + int i, j, k, size = 0, found = 0; _GLFWmonitor** monitors = NULL; *count = 0; if (_glfw.x11.randr.available) { + int screenCount = 0; + XineramaScreenInfo* screens = NULL; XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); RROutput primary = XRRGetOutputPrimary(_glfw.x11.display, _glfw.x11.root); + if (_glfw.x11.xinerama.available) + screens = XineramaQueryScreens(_glfw.x11.display, &screenCount); + for (i = 0; i < sr->ncrtc; i++) { XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, @@ -240,6 +245,18 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) monitors[found]->x11.output = ci->outputs[j]; 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); if (ci->outputs[j] == primary) @@ -253,6 +270,9 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) XRRFreeScreenResources(sr); + if (screens) + XFree(screens); + if (found == 0) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/x11_platform.h b/src/x11_platform.h index 7c4e72e2..a69705b3 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -48,6 +48,9 @@ // The Xkb extension provides improved keyboard support #include +// The Xinerama extension provides legacy monitor indices +#include + #include "posix_tls.h" #if defined(_GLFW_GLX) @@ -130,6 +133,7 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_STATE_ABOVE; Atom NET_WM_STATE_FULLSCREEN; Atom NET_WM_BYPASS_COMPOSITOR; + Atom NET_WM_FULLSCREEN_MONITORS; Atom NET_ACTIVE_WINDOW; Atom NET_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS; @@ -205,6 +209,12 @@ typedef struct _GLFWlibraryX11 Window source; } xdnd; + struct { + GLboolean available; + int versionMajor; + int versionMinor; + } xinerama; + } _GLFWlibraryX11; @@ -216,6 +226,10 @@ typedef struct _GLFWmonitorX11 RRCrtc crtc; RRMode oldMode; + // Index of corresponding Xinerama screen, + // for EWMH full screen window placement + int index; + } _GLFWmonitorX11; diff --git a/src/x11_window.c b/src/x11_window.c index ce3d8a66..dfc303fd 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -715,6 +715,27 @@ static void enterFullscreenMode(_GLFWwindow* window) 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) { int x, y;