| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- #include "CX11FullScreenDetector.h"
- #include "WallpaperEngine/Logging/CLog.h"
- #include <X11/Xlib.h>
- #include <X11/extensions/Xrandr.h>
- #include "WallpaperEngine/Render/Drivers/CX11OpenGLDriver.h"
- namespace WallpaperEngine::Render::Drivers::Detectors
- {
- void CustomXIOErrorExitHandler (Display* dsp, void* userdata)
- {
- auto context = static_cast <CX11FullScreenDetector*> (userdata);
- sLog.debugerror ("Critical XServer error detected. Attempting to recover...");
- // refetch all the resources
- context->reset ();
- }
- int CustomXErrorHandler (Display* dpy, XErrorEvent* event)
- {
- sLog.debugerror ("Detected X error");
- return 0;
- }
- int CustomXIOErrorHandler (Display* dsp)
- {
- sLog.debugerror ("Detected X error");
- return 0;
- }
- CX11FullScreenDetector::CX11FullScreenDetector (Application::CApplicationContext& appContext, CX11OpenGLDriver& driver) :
- CFullScreenDetector (appContext),
- m_driver (driver)
- {
- // do not use previous handler, it might stop the app under weird circumstances
- // these handlers might be replaced by other X11-specific functionality, they
- // should only be used to ignore X11 errors and nothing else
- // so this doesn't affect functionality
- XSetErrorHandler (CustomXErrorHandler);
- XSetIOErrorHandler (CustomXIOErrorHandler);
- this->initialize ();
- }
- CX11FullScreenDetector::~CX11FullScreenDetector ()
- {
- this->stop ();
- }
- bool CX11FullScreenDetector::anythingFullscreen () const
- {
- if (!this->getApplicationContext ().settings.render.pauseOnFullscreen)
- return false;
- // stop rendering if anything is fullscreen
- bool isFullscreen = false;
- XWindowAttributes attribs;
- Window _;
- Window* children;
- unsigned int nchildren;
- isFullscreen = false;
- if (!XQueryTree (this->m_display, this->m_root, &_, &_, &children, &nchildren))
- return false;
- auto ourWindow = reinterpret_cast <Window> (this->m_driver.getWindow ());
- Window parentWindow;
- {
- Window root, * schildren = NULL;
- unsigned int num_children;
- if (!XQueryTree (m_display, ourWindow, &root, &parentWindow, &schildren, &num_children))
- return false;
- if (schildren)
- XFree ((char*) children);
- }
- for (int i = 0; i < nchildren; i++)
- {
- if (!XGetWindowAttributes (this->m_display, children [i], &attribs))
- continue;
- // ignore ourselves
- if (ourWindow == children [i] || parentWindow == children [i])
- 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);
- return isFullscreen;
- }
- void CX11FullScreenDetector::reset ()
- {
- this->stop ();
- this->initialize ();
- }
- void CX11FullScreenDetector::initialize ()
- {
- 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 */
- int xrandr_result, xrandr_error;
- if (!XRRQueryExtension (this->m_display, &xrandr_result, &xrandr_error))
- {
- sLog.error ("XRandr is not present, fullscreen detection might not work");
- return;
- }
- this->m_root = DefaultRootWindow (this->m_display);
- XRRScreenResources* screenResources = XRRGetScreenResources (this->m_display, this->m_root);
- if (screenResources == nullptr)
- {
- sLog.error ("Cannot detect screen sizes using xrandr, fullscreen detection might not work");
- return;
- }
- for (int i = 0; i < screenResources->noutput; i ++)
- {
- XRROutputInfo* info = XRRGetOutputInfo (this->m_display, screenResources, screenResources->outputs [i]);
- // screen not in use, ignore it
- if (info == nullptr || info->connection != RR_Connected)
- continue;
- XRRCrtcInfo* crtc = XRRGetCrtcInfo (this->m_display, screenResources, info->crtc);
- // screen not active, ignore it
- if (crtc == nullptr)
- continue;
- // add the screen to the list of screens
- this->m_screens.push_back (
- {
- {crtc->x, crtc->y, crtc->width, crtc->height},
- info->name
- }
- );
- XRRFreeCrtcInfo (crtc);
- }
- XRRFreeScreenResources (screenResources);
- }
- void CX11FullScreenDetector::stop ()
- {
- if (this->m_display == nullptr)
- return;
- XCloseDisplay (this->m_display);
- this->m_display = nullptr;
- }
- }
|