Explorar el Código

Added support for detecting full-screen windows on X11 output

Signed-off-by: Alexis Maiquez <almamu@almamu.com>
Alexis Maiquez hace 3 años
padre
commit
6802511bb9

+ 72 - 17
src/WallpaperEngine/Render/Drivers/Output/CX11Output.cpp

@@ -1,13 +1,14 @@
 #include "common.h"
 #include "CX11Output.h"
 
+#include <unistd.h>
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
 #include <X11/extensions/Xrandr.h>
 
-using namespace WallpaperEngine::Render::Drivers::Output;
+#define FULLSCREEN_CHECK_WAIT_TIME 250
 
-XErrorHandler originalErrorHandler;
+using namespace WallpaperEngine::Render::Drivers::Output;
 
 void CustomXIOErrorExitHandler (Display* dsp, void* userdata)
 {
@@ -24,7 +25,7 @@ int CustomXErrorHandler (Display* dpy, XErrorEvent* event)
     sLog.debugerror ("Detected X error");
 
     // call the original handler so we can keep some information reporting
-    originalErrorHandler (dpy, event);
+    // originalErrorHandler (dpy, event);
 
     return 0;
 }
@@ -40,13 +41,16 @@ CX11Output::CX11Output (CApplicationContext& context, CVideoDriver& driver) :
 	COutput (context),
 	m_driver (driver)
 {
-	this->m_display = XOpenDisplay (nullptr);
+	// do not use previous handler, it might stop the app under weird circumstances
+	XSetErrorHandler (CustomXErrorHandler);
+	XSetIOErrorHandler (CustomXIOErrorHandler);
+
 	this->loadScreenInfo ();
 }
+
 CX11Output::~CX11Output ()
 {
 	this->free ();
-	XCloseDisplay (this->m_display);
 }
 
 void CX11Output::reset ()
@@ -64,6 +68,7 @@ void CX11Output::free ()
 	XFreeGC (this->m_display, this->m_gc);
 	XFreePixmap (this->m_display, this->m_pixmap);
 	delete this->m_imageData;
+	XCloseDisplay (this->m_display);
 }
 
 void* CX11Output::getImageBuffer () const
@@ -91,12 +96,11 @@ void CX11Output::loadScreenInfo ()
 	// reset the viewports
 	this->m_viewports.clear ();
 
+	this->m_display = XOpenDisplay (nullptr);
     // set the error handling to try and recover from X disconnections
 #ifdef HAVE_XSETIOERROREXITHANDLER
     XSetIOErrorExitHandler (this->m_display, CustomXIOErrorExitHandler, this);
 #endif /* HAVE_XSETIOERROREXITHANDLER */
-    originalErrorHandler = XSetErrorHandler (CustomXErrorHandler);
-    XSetIOErrorHandler (CustomXIOErrorHandler);
 
 	int xrandr_result, xrandr_error;
 
@@ -125,19 +129,27 @@ void CX11Output::loadScreenInfo ()
 		if (info == nullptr || info->connection != RR_Connected)
 			continue;
 
-		// only keep info of registered screens
-		if (this->m_context.screenSettings.find (info->name) == this->m_context.screenSettings.end ())
-			continue;
-
 		XRRCrtcInfo* crtc = XRRGetCrtcInfo (this->m_display, screenResources, info->crtc);
 
-		sLog.out ("Found requested screen: ", info->name, " -> ", crtc->x, "x", crtc->y, ":", crtc->width, "x", crtc->height);
+		// add the screen to the list of screens
+		this->m_screens.push_back (
+			{
+				{crtc->x, crtc->y, crtc->width, crtc->height},
+				info->name
+			}
+		);
 
-		this->m_viewports [info->name] =
+		// only keep info of registered screens
+		if (this->m_context.screenSettings.find (info->name) != this->m_context.screenSettings.end ())
 		{
-			{crtc->x, crtc->y, crtc->width, crtc->height},
-			info->name
-		};
+			sLog.out ("Found requested screen: ", info->name, " -> ", crtc->x, "x", crtc->y, ":", crtc->width, "x", crtc->height);
+
+			this->m_viewports[info->name] =
+			{
+				{crtc->x, crtc->y, crtc->width, crtc->height},
+				info->name
+			};
+		}
 
 		XRRFreeCrtcInfo (crtc);
 	}
@@ -174,4 +186,47 @@ void CX11Output::updateRender () const
 
     XClearWindow(this->m_display, this->m_root);
     XFlush(this->m_display);
-}
+
+	// stop rendering if anything is fullscreen
+	bool isFullscreen = false;
+	XWindowAttributes attribs;
+	Window _;
+	Window* children;
+	unsigned int nchildren;
+
+	do
+	{
+		isFullscreen = false;
+
+		if (!XQueryTree (this->m_display, this->m_root, &_, &_, &children, &nchildren))
+			return;
+
+		for (int i = 0; i < nchildren; i++)
+		{
+			if (!XGetWindowAttributes (this->m_display, children [i], &attribs))
+				continue;
+
+			if (attribs.map_state != IsViewable)
+				continue;
+
+			// compare width and height with the different screens we have
+			for (const auto& screen : this->m_screens)
+			{
+				if (
+					attribs.x == screen.viewport.x && attribs.y == screen.viewport.y &&
+					attribs.width == screen.viewport.z && attribs.height == screen.viewport.w
+				)
+				{
+					isFullscreen = true;
+					break;
+				}
+			}
+		}
+
+		XFree (children);
+
+		// give the cpu some time to check again later
+		usleep (FULLSCREEN_CHECK_WAIT_TIME);
+	}
+	while (isFullscreen);
+}

+ 1 - 0
src/WallpaperEngine/Render/Drivers/Output/CX11Output.h

@@ -36,5 +36,6 @@ namespace WallpaperEngine::Render::Drivers::Output
 		char* m_imageData;
 		XImage* m_image;
 		CVideoDriver& m_driver;
+		std::vector <ScreenInfo> m_screens;
 	};
 }