Bläddra i källkod

Separated X11 fullscreen code detection from the output driver as they don't have to work at the same time

Signed-off-by: Alexis Maiquez <almamu@almamu.com>
Alexis Maiquez 3 år sedan
förälder
incheckning
cc7ec0561d
30 ändrade filer med 345 tillägg och 97 borttagningar
  1. 7 2
      CMakeLists.txt
  2. 8 5
      src/WallpaperEngine/Application/CWallpaperApplication.cpp
  3. 1 1
      src/WallpaperEngine/Application/CWallpaperApplication.h
  4. 1 1
      src/WallpaperEngine/Audio/CAudioStream.h
  5. 2 2
      src/WallpaperEngine/Input/CInputContext.cpp
  6. 4 4
      src/WallpaperEngine/Input/CInputContext.h
  7. 1 0
      src/WallpaperEngine/Input/CMouseInput.h
  8. 1 0
      src/WallpaperEngine/Render/CObject.cpp
  9. 2 1
      src/WallpaperEngine/Render/CObject.h
  10. 4 0
      src/WallpaperEngine/Render/Drivers/CVideoDriver.h
  11. 21 13
      src/WallpaperEngine/Render/Drivers/CX11OpenGLDriver.cpp
  12. 4 3
      src/WallpaperEngine/Render/Drivers/CX11OpenGLDriver.h
  13. 1 0
      src/WallpaperEngine/Render/Drivers/Detectors/CFullScreenDetector.cpp
  14. 18 0
      src/WallpaperEngine/Render/Drivers/Detectors/CFullScreenDetector.h
  15. 176 0
      src/WallpaperEngine/Render/Drivers/Detectors/CX11FullScreenDetector.cpp
  16. 38 0
      src/WallpaperEngine/Render/Drivers/Detectors/CX11FullScreenDetector.h
  17. 10 2
      src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.cpp
  18. 1 1
      src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.h
  19. 3 2
      src/WallpaperEngine/Render/Drivers/Output/COutput.cpp
  20. 8 1
      src/WallpaperEngine/Render/Drivers/Output/COutput.h
  21. 6 46
      src/WallpaperEngine/Render/Drivers/Output/CX11Output.cpp
  22. 1 1
      src/WallpaperEngine/Render/Drivers/Output/CX11Output.h
  23. 5 0
      src/WallpaperEngine/Render/Helpers/CContextAware.cpp
  24. 4 0
      src/WallpaperEngine/Render/Helpers/CContextAware.h
  25. 1 1
      src/WallpaperEngine/Render/Objects/CImage.cpp
  26. 1 1
      src/WallpaperEngine/Render/Objects/CSound.cpp
  27. 1 0
      src/WallpaperEngine/Render/Objects/Effects/CMaterial.cpp
  28. 7 5
      src/WallpaperEngine/Render/Objects/Effects/CMaterial.h
  29. 5 4
      src/WallpaperEngine/Render/Objects/Effects/CPass.cpp
  30. 3 1
      src/WallpaperEngine/Render/Objects/Effects/CPass.h

+ 7 - 2
CMakeLists.txt

@@ -108,14 +108,19 @@ add_executable(
     src/WallpaperEngine/Render/Helpers/CContextAware.cpp
     src/WallpaperEngine/Render/Helpers/CContextAware.cpp
     src/WallpaperEngine/Render/Helpers/CContextAware.h
     src/WallpaperEngine/Render/Helpers/CContextAware.h
 
 
+    src/WallpaperEngine/Render/Drivers/Detectors/CFullScreenDetector.cpp
+    src/WallpaperEngine/Render/Drivers/Detectors/CFullScreenDetector.h
+    src/WallpaperEngine/Render/Drivers/Detectors/CX11FullScreenDetector.cpp
+    src/WallpaperEngine/Render/Drivers/Detectors/CX11FullScreenDetector.h
+
     src/WallpaperEngine/Render/Drivers/Output/COutput.cpp
     src/WallpaperEngine/Render/Drivers/Output/COutput.cpp
     src/WallpaperEngine/Render/Drivers/Output/COutput.h
     src/WallpaperEngine/Render/Drivers/Output/COutput.h
     src/WallpaperEngine/Render/Drivers/Output/CX11Output.cpp
     src/WallpaperEngine/Render/Drivers/Output/CX11Output.cpp
     src/WallpaperEngine/Render/Drivers/Output/CX11Output.h
     src/WallpaperEngine/Render/Drivers/Output/CX11Output.h
     src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.cpp
     src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.cpp
     src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.h
     src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.h
-    src/WallpaperEngine/Render/Drivers/COpenGLDriver.h
-    src/WallpaperEngine/Render/Drivers/COpenGLDriver.cpp
+    src/WallpaperEngine/Render/Drivers/CX11OpenGLDriver.h
+    src/WallpaperEngine/Render/Drivers/CX11OpenGLDriver.cpp
     src/WallpaperEngine/Render/Drivers/CVideoDriver.h
     src/WallpaperEngine/Render/Drivers/CVideoDriver.h
     src/WallpaperEngine/Render/Drivers/CVideoDriver.cpp
     src/WallpaperEngine/Render/Drivers/CVideoDriver.cpp
     src/WallpaperEngine/Render/CRenderContext.h
     src/WallpaperEngine/Render/CRenderContext.h

+ 8 - 5
src/WallpaperEngine/Application/CWallpaperApplication.cpp

@@ -10,6 +10,7 @@
 #include "WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.h"
 #include "WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.h"
 #include "WallpaperEngine/Render/Drivers/Output/CX11Output.h"
 #include "WallpaperEngine/Render/Drivers/Output/CX11Output.h"
 #include "WallpaperEngine/Application/CApplicationState.h"
 #include "WallpaperEngine/Application/CApplicationState.h"
+#include "WallpaperEngine/Render/Drivers/Detectors/CX11FullScreenDetector.h"
 
 
 #include <unistd.h>
 #include <unistd.h>
 
 
@@ -65,7 +66,7 @@ namespace WallpaperEngine::Application
             );
             );
 
 
         // TODO: move this somewhere else?
         // TODO: move this somewhere else?
-        CVirtualContainer* virtualContainer = new CVirtualContainer ();
+        auto* virtualContainer = new CVirtualContainer ();
 
 
         //
         //
         // Had to get a little creative with the effects to achieve the same bloom effect without any custom code
         // Had to get a little creative with the effects to achieve the same bloom effect without any custom code
@@ -183,7 +184,7 @@ namespace WallpaperEngine::Application
 
 
     Core::CProject* CWallpaperApplication::loadBackground (const std::string& bg)
     Core::CProject* CWallpaperApplication::loadBackground (const std::string& bg)
     {
     {
-        CCombinedContainer* container = new CCombinedContainer ();
+        auto* container = new CCombinedContainer ();
 
 
         this->setupContainer (*container, bg);
         this->setupContainer (*container, bg);
 
 
@@ -269,22 +270,24 @@ namespace WallpaperEngine::Application
         // initialize audio context
         // initialize audio context
         WallpaperEngine::Audio::CAudioContext audioContext (audioDriver);
         WallpaperEngine::Audio::CAudioContext audioContext (audioDriver);
         // initialize OpenGL driver
         // initialize OpenGL driver
-        WallpaperEngine::Render::Drivers::COpenGLDriver videoDriver ("wallpaperengine");
+        WallpaperEngine::Render::Drivers::CX11OpenGLDriver videoDriver ("wallpaperengine");
         // initialize the input subsystem
         // initialize the input subsystem
         WallpaperEngine::Input::CInputContext inputContext (videoDriver);
         WallpaperEngine::Input::CInputContext inputContext (videoDriver);
         // output requested
         // output requested
         WallpaperEngine::Render::Drivers::Output::COutput* output;
         WallpaperEngine::Render::Drivers::Output::COutput* output;
+        // fullscreen detector is common for the different render modes
+        WallpaperEngine::Render::Drivers::Detectors::CX11FullScreenDetector fullscreenDetector (videoDriver);
 
 
         // initialize the requested output
         // initialize the requested output
         switch (this->m_context.settings.render.mode)
         switch (this->m_context.settings.render.mode)
         {
         {
             case CApplicationContext::EXPLICIT_WINDOW:
             case CApplicationContext::EXPLICIT_WINDOW:
             case CApplicationContext::NORMAL_WINDOW:
             case CApplicationContext::NORMAL_WINDOW:
-                output = new WallpaperEngine::Render::Drivers::Output::CGLFWWindowOutput (this->m_context, videoDriver);
+                output = new WallpaperEngine::Render::Drivers::Output::CGLFWWindowOutput (this->m_context, videoDriver, fullscreenDetector);
                 break;
                 break;
 
 
             case CApplicationContext::X11_BACKGROUND:
             case CApplicationContext::X11_BACKGROUND:
-                output = new WallpaperEngine::Render::Drivers::Output::CX11Output (this->m_context, videoDriver);
+                output = new WallpaperEngine::Render::Drivers::Output::CX11Output (this->m_context, videoDriver, fullscreenDetector);
                 break;
                 break;
         }
         }
 
 

+ 1 - 1
src/WallpaperEngine/Application/CWallpaperApplication.h

@@ -8,7 +8,7 @@
 
 
 #include "WallpaperEngine/Render/CWallpaper.h"
 #include "WallpaperEngine/Render/CWallpaper.h"
 #include "WallpaperEngine/Render/CRenderContext.h"
 #include "WallpaperEngine/Render/CRenderContext.h"
-#include "WallpaperEngine/Render/Drivers/COpenGLDriver.h"
+#include "WallpaperEngine/Render/Drivers/CX11OpenGLDriver.h"
 
 
 namespace WallpaperEngine::Application
 namespace WallpaperEngine::Application
 {
 {

+ 1 - 1
src/WallpaperEngine/Audio/CAudioStream.h

@@ -46,7 +46,7 @@ namespace WallpaperEngine::Audio
         /**
         /**
          * @return The audio context in use for this audio stream
          * @return The audio context in use for this audio stream
          */
          */
-        CAudioContext& getAudioContext () const;
+        [[nodiscard]] CAudioContext& getAudioContext () const;
 
 
         /**
         /**
          * @return to the codec context, which provides information on the audio stream's format
          * @return to the codec context, which provides information on the audio stream's format

+ 2 - 2
src/WallpaperEngine/Input/CInputContext.cpp

@@ -1,10 +1,10 @@
 #include "CInputContext.h"
 #include "CInputContext.h"
-#include "WallpaperEngine/Render/Drivers/COpenGLDriver.h"
+#include "WallpaperEngine/Render/Drivers/CX11OpenGLDriver.h"
 
 
 using namespace WallpaperEngine::Input;
 using namespace WallpaperEngine::Input;
 using namespace WallpaperEngine::Render::Drivers;
 using namespace WallpaperEngine::Render::Drivers;
 
 
-CInputContext::CInputContext (COpenGLDriver& videoDriver) :
+CInputContext::CInputContext (CX11OpenGLDriver& videoDriver) :
     m_mouse (videoDriver.getWindow ())
     m_mouse (videoDriver.getWindow ())
 {
 {
 }
 }

+ 4 - 4
src/WallpaperEngine/Input/CInputContext.h

@@ -1,11 +1,11 @@
 #pragma once
 #pragma once
 
 
-#include "WallpaperEngine/Render/Drivers/COpenGLDriver.h"
+#include "WallpaperEngine/Render/Drivers/CX11OpenGLDriver.h"
 #include "CMouseInput.h"
 #include "CMouseInput.h"
 
 
 namespace WallpaperEngine::Render::Drivers
 namespace WallpaperEngine::Render::Drivers
 {
 {
-    class COpenGLDriver;
+    class CX11OpenGLDriver;
 }
 }
 
 
 namespace WallpaperEngine::Input
 namespace WallpaperEngine::Input
@@ -13,10 +13,10 @@ namespace WallpaperEngine::Input
     class CInputContext
     class CInputContext
     {
     {
     public:
     public:
-        explicit CInputContext (Render::Drivers::COpenGLDriver& videoDriver);
+        explicit CInputContext (Render::Drivers::CX11OpenGLDriver& videoDriver);
         void update ();
         void update ();
 
 
-        const CMouseInput& getMouseInput () const;
+        [[nodiscard]] const CMouseInput& getMouseInput () const;
 
 
     private:
     private:
         CMouseInput m_mouse;
         CMouseInput m_mouse;

+ 1 - 0
src/WallpaperEngine/Input/CMouseInput.h

@@ -22,6 +22,7 @@ namespace WallpaperEngine::Input
          * The virtual pointer's position
          * The virtual pointer's position
          */
          */
         glm::dvec2 position;
         glm::dvec2 position;
+
     private:
     private:
         /**
         /**
          * The GLFW window to get mouse position from
          * The GLFW window to get mouse position from

+ 1 - 0
src/WallpaperEngine/Render/CObject.cpp

@@ -6,6 +6,7 @@ using namespace WallpaperEngine;
 using namespace WallpaperEngine::Render;
 using namespace WallpaperEngine::Render;
 
 
 CObject::CObject(CScene* scene, std::string type, Core::CObject *object) :
 CObject::CObject(CScene* scene, std::string type, Core::CObject *object) :
+    Helpers::CContextAware (scene),
     m_scene (scene),
     m_scene (scene),
     m_object (object),
     m_object (object),
     m_type (std::move (type))
     m_type (std::move (type))

+ 2 - 1
src/WallpaperEngine/Render/CObject.h

@@ -3,6 +3,7 @@
 #include <string>
 #include <string>
 
 
 #include "WallpaperEngine/Core/CObject.h"
 #include "WallpaperEngine/Core/CObject.h"
+#include "WallpaperEngine/Render/Helpers/CContextAware.h"
 
 
 #include "CScene.h"
 #include "CScene.h"
 
 
@@ -10,7 +11,7 @@ namespace WallpaperEngine::Render
 {
 {
     class CScene;
     class CScene;
 
 
-    class CObject
+    class CObject : public Helpers::CContextAware
     {
     {
     public:
     public:
         template<class T> const T* as () const { assert (is<T>()); return (const T*) this; }
         template<class T> const T* as () const { assert (is<T>()); return (const T*) this; }

+ 4 - 0
src/WallpaperEngine/Render/Drivers/CVideoDriver.h

@@ -8,6 +8,10 @@ namespace WallpaperEngine::Render::Drivers
     class CVideoDriver
     class CVideoDriver
     {
     {
     public:
     public:
+        /**
+         * @return The window handle used by this video driver
+         */
+        virtual void* getWindowHandle () const = 0;
         /**
         /**
          * @return The time that has passed since the driver started
          * @return The time that has passed since the driver started
          */
          */

+ 21 - 13
src/WallpaperEngine/Render/Drivers/COpenGLDriver.cpp → src/WallpaperEngine/Render/Drivers/CX11OpenGLDriver.cpp

@@ -1,7 +1,10 @@
-#include "COpenGLDriver.h"
+#include "CX11OpenGLDriver.h"
 #include "common.h"
 #include "common.h"
 #include <FreeImage.h>
 #include <FreeImage.h>
 
 
+#define GLFW_EXPOSE_NATIVE_X11
+#include <GLFW/glfw3native.h>
+
 using namespace WallpaperEngine::Render::Drivers;
 using namespace WallpaperEngine::Render::Drivers;
 
 
 void CustomGLFWErrorHandler (int errorCode, const char* reason)
 void CustomGLFWErrorHandler (int errorCode, const char* reason)
@@ -9,7 +12,7 @@ void CustomGLFWErrorHandler (int errorCode, const char* reason)
     sLog.error ("GLFW error ", errorCode, ": ", reason);
     sLog.error ("GLFW error ", errorCode, ": ", reason);
 }
 }
 
 
-COpenGLDriver::COpenGLDriver (const char* windowTitle) :
+CX11OpenGLDriver::CX11OpenGLDriver (const char* windowTitle) :
     m_frameCounter (0)
     m_frameCounter (0)
 {
 {
     glfwSetErrorCallback (CustomGLFWErrorHandler);
     glfwSetErrorCallback (CustomGLFWErrorHandler);
@@ -48,44 +51,49 @@ COpenGLDriver::COpenGLDriver (const char* windowTitle) :
     FreeImage_Initialise (TRUE);
     FreeImage_Initialise (TRUE);
 }
 }
 
 
-COpenGLDriver::~COpenGLDriver ()
+CX11OpenGLDriver::~CX11OpenGLDriver ()
 {
 {
     glfwTerminate ();
     glfwTerminate ();
     FreeImage_DeInitialise();
     FreeImage_DeInitialise();
 }
 }
 
 
-float COpenGLDriver::getRenderTime () const
+void* CX11OpenGLDriver::getWindowHandle () const
+{
+    return reinterpret_cast <void*> (glfwGetX11Window (this->m_window));
+}
+
+float CX11OpenGLDriver::getRenderTime () const
 {
 {
     return (float) glfwGetTime ();
     return (float) glfwGetTime ();
 }
 }
 
 
-bool COpenGLDriver::closeRequested ()
+bool CX11OpenGLDriver::closeRequested ()
 {
 {
     return glfwWindowShouldClose (this->m_window);
     return glfwWindowShouldClose (this->m_window);
 }
 }
 
 
-void COpenGLDriver::resizeWindow (glm::ivec2 size)
+void CX11OpenGLDriver::resizeWindow (glm::ivec2 size)
 {
 {
     glfwSetWindowSize (this->m_window, size.x, size.y);
     glfwSetWindowSize (this->m_window, size.x, size.y);
 }
 }
 
 
-void COpenGLDriver::resizeWindow (glm::ivec4 sizeandpos)
+void CX11OpenGLDriver::resizeWindow (glm::ivec4 sizeandpos)
 {
 {
     glfwSetWindowPos (this->m_window, sizeandpos.x, sizeandpos.y);
     glfwSetWindowPos (this->m_window, sizeandpos.x, sizeandpos.y);
     glfwSetWindowSize (this->m_window, sizeandpos.z, sizeandpos.w);
     glfwSetWindowSize (this->m_window, sizeandpos.z, sizeandpos.w);
 }
 }
 
 
-void COpenGLDriver::showWindow ()
+void CX11OpenGLDriver::showWindow ()
 {
 {
     glfwShowWindow (this->m_window);
     glfwShowWindow (this->m_window);
 }
 }
 
 
-void COpenGLDriver::hideWindow ()
+void CX11OpenGLDriver::hideWindow ()
 {
 {
     glfwHideWindow (this->m_window);
     glfwHideWindow (this->m_window);
 }
 }
 
 
-glm::ivec2 COpenGLDriver::getFramebufferSize () const
+glm::ivec2 CX11OpenGLDriver::getFramebufferSize () const
 {
 {
     glm::ivec2 size;
     glm::ivec2 size;
 
 
@@ -94,7 +102,7 @@ glm::ivec2 COpenGLDriver::getFramebufferSize () const
     return size;
     return size;
 }
 }
 
 
-void COpenGLDriver::swapBuffers ()
+void CX11OpenGLDriver::swapBuffers ()
 {
 {
     // do buffer swapping first
     // do buffer swapping first
     glfwSwapBuffers (this->m_window);
     glfwSwapBuffers (this->m_window);
@@ -104,12 +112,12 @@ void COpenGLDriver::swapBuffers ()
     this->m_frameCounter ++;
     this->m_frameCounter ++;
 }
 }
 
 
-uint32_t COpenGLDriver::getFrameCounter () const
+uint32_t CX11OpenGLDriver::getFrameCounter () const
 {
 {
     return this->m_frameCounter;
     return this->m_frameCounter;
 }
 }
 
 
-GLFWwindow* COpenGLDriver::getWindow ()
+GLFWwindow* CX11OpenGLDriver::getWindow ()
 {
 {
     return this->m_window;
     return this->m_window;
 }
 }

+ 4 - 3
src/WallpaperEngine/Render/Drivers/COpenGLDriver.h → src/WallpaperEngine/Render/Drivers/CX11OpenGLDriver.h

@@ -14,12 +14,13 @@ namespace WallpaperEngine::Render::Drivers
 {
 {
     using namespace WallpaperEngine::Application;
     using namespace WallpaperEngine::Application;
 
 
-    class COpenGLDriver : public CVideoDriver
+    class CX11OpenGLDriver : public CVideoDriver
     {
     {
     public:
     public:
-        explicit COpenGLDriver (const char* windowTitle);
-        ~COpenGLDriver();
+        explicit CX11OpenGLDriver (const char* windowTitle);
+        ~CX11OpenGLDriver();
 
 
+        void* getWindowHandle () const;
         float getRenderTime () const override;
         float getRenderTime () const override;
         bool closeRequested () override;
         bool closeRequested () override;
         void resizeWindow (glm::ivec2 size) override;
         void resizeWindow (glm::ivec2 size) override;

+ 1 - 0
src/WallpaperEngine/Render/Drivers/Detectors/CFullScreenDetector.cpp

@@ -0,0 +1 @@
+#include "CFullScreenDetector.h"

+ 18 - 0
src/WallpaperEngine/Render/Drivers/Detectors/CFullScreenDetector.h

@@ -0,0 +1,18 @@
+#pragma once
+
+namespace WallpaperEngine::Render::Drivers::Detectors
+{
+    class CFullScreenDetector
+    {
+    public:
+        /**
+         * @return If anything is fullscreen
+         */
+        [[nodiscard]] virtual bool anythingFullscreen () const = 0;
+
+        /**
+         * Restarts the fullscreen detector, specially useful if there's any resources tied to the output driver
+         */
+        virtual void reset () = 0;
+    };
+}

+ 176 - 0
src/WallpaperEngine/Render/Drivers/Detectors/CX11FullScreenDetector.cpp

@@ -0,0 +1,176 @@
+#include "CX11FullScreenDetector.h"
+#include "WallpaperEngine/Logging/CLog.h"
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xrandr.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 (CVideoDriver& driver) :
+        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
+    {
+        // 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.getWindowHandle ());
+        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);
+
+            // 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;
+    }
+
+}

+ 38 - 0
src/WallpaperEngine/Render/Drivers/Detectors/CX11FullScreenDetector.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <glm/vec4.hpp>
+
+#include "CFullScreenDetector.h"
+#include "WallpaperEngine/Render/Drivers/CVideoDriver.h"
+
+#include <X11/Xlib.h>
+
+namespace WallpaperEngine::Render::Drivers::Detectors
+{
+    class CX11FullScreenDetector : public  CFullScreenDetector
+    {
+    public:
+        CX11FullScreenDetector (CVideoDriver& driver);
+        ~CX11FullScreenDetector ();
+
+        [[nodiscard]] bool anythingFullscreen () const override;
+        void reset () override;
+
+    private:
+        void initialize ();
+        void stop ();
+
+        struct ScreenInfo
+        {
+            glm::ivec4 viewport;
+            std::string name;
+        };
+
+        Display* m_display;
+        Window m_root;
+        std::vector <ScreenInfo> m_screens;
+        CVideoDriver& m_driver;
+    };
+}

+ 10 - 2
src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.cpp

@@ -2,10 +2,14 @@
 #include "CGLFWWindowOutput.h"
 #include "CGLFWWindowOutput.h"
 #include "WallpaperEngine/Logging/CLog.h"
 #include "WallpaperEngine/Logging/CLog.h"
 
 
+#include <unistd.h>
+
+#define FULLSCREEN_CHECK_WAIT_TIME 250
+
 using namespace WallpaperEngine::Render::Drivers::Output;
 using namespace WallpaperEngine::Render::Drivers::Output;
 
 
-CGLFWWindowOutput::CGLFWWindowOutput (CApplicationContext& context, CVideoDriver& driver) :
-    COutput (context),
+CGLFWWindowOutput::CGLFWWindowOutput (CApplicationContext& context, CVideoDriver& driver, Detectors::CFullScreenDetector& detector) :
+    COutput (context, detector),
     m_driver (driver)
     m_driver (driver)
 {
 {
     if (
     if (
@@ -75,4 +79,8 @@ void CGLFWWindowOutput::updateRender () const
 
 
     // update the default viewport
     // update the default viewport
     this->m_viewports ["default"] = {{0, 0, this->m_fullWidth, this->m_fullHeight}, "default"};
     this->m_viewports ["default"] = {{0, 0, this->m_fullWidth, this->m_fullHeight}, "default"};
+
+    // check for fullscreen windows and wait until there's none fullscreen
+    while (this->m_detector.anythingFullscreen () && this->m_context.state.general.keepRunning)
+        usleep (FULLSCREEN_CHECK_WAIT_TIME);
 }
 }

+ 1 - 1
src/WallpaperEngine/Render/Drivers/Output/CGLFWWindowOutput.h

@@ -8,7 +8,7 @@ namespace WallpaperEngine::Render::Drivers::Output
     class CGLFWWindowOutput : public COutput
     class CGLFWWindowOutput : public COutput
     {
     {
     public:
     public:
-        CGLFWWindowOutput (CApplicationContext& context, CVideoDriver& driver);
+        CGLFWWindowOutput (CApplicationContext& context, CVideoDriver& driver, Detectors::CFullScreenDetector& detector);
 
 
         void reset () override;
         void reset () override;
         bool renderVFlip () const override;
         bool renderVFlip () const override;

+ 3 - 2
src/WallpaperEngine/Render/Drivers/Output/COutput.cpp

@@ -2,8 +2,9 @@
 
 
 using namespace WallpaperEngine::Render::Drivers::Output;
 using namespace WallpaperEngine::Render::Drivers::Output;
 
 
-COutput::COutput (CApplicationContext& context) :
-    m_context (context)
+COutput::COutput (CApplicationContext& context, Detectors::CFullScreenDetector& detector) :
+    m_context (context),
+    m_detector (detector)
 {
 {
 }
 }
 
 

+ 8 - 1
src/WallpaperEngine/Render/Drivers/Output/COutput.h

@@ -5,6 +5,7 @@
 #include <glm/vec4.hpp>
 #include <glm/vec4.hpp>
 
 
 #include "WallpaperEngine/Application/CApplicationContext.h"
 #include "WallpaperEngine/Application/CApplicationContext.h"
+#include "WallpaperEngine/Render/Drivers/Detectors/CFullScreenDetector.h"
 
 
 using namespace WallpaperEngine::Application;
 using namespace WallpaperEngine::Application;
 
 
@@ -13,12 +14,17 @@ namespace WallpaperEngine::Application
     class CApplicationContext;
     class CApplicationContext;
 }
 }
 
 
+namespace WallpaperEngine::Render::Drivers::Detectors
+{
+    class CFullScreenDetector;
+}
+
 namespace WallpaperEngine::Render::Drivers::Output
 namespace WallpaperEngine::Render::Drivers::Output
 {
 {
     class COutput
     class COutput
     {
     {
     public:
     public:
-        COutput (CApplicationContext& context);
+        COutput (CApplicationContext& context, Detectors::CFullScreenDetector& detector);
 
 
         virtual void reset () = 0;
         virtual void reset () = 0;
 
 
@@ -43,5 +49,6 @@ namespace WallpaperEngine::Render::Drivers::Output
         mutable int m_fullHeight;
         mutable int m_fullHeight;
         mutable std::map <std::string, ScreenInfo> m_viewports;
         mutable std::map <std::string, ScreenInfo> m_viewports;
         CApplicationContext& m_context;
         CApplicationContext& m_context;
+        Detectors::CFullScreenDetector& m_detector;
     };
     };
 }
 }

+ 6 - 46
src/WallpaperEngine/Render/Drivers/Output/CX11Output.cpp

@@ -24,9 +24,6 @@ int CustomXErrorHandler (Display* dpy, XErrorEvent* event)
 {
 {
     sLog.debugerror ("Detected X error");
     sLog.debugerror ("Detected X error");
 
 
-    // call the original handler so we can keep some information reporting
-    // originalErrorHandler (dpy, event);
-
     return 0;
     return 0;
 }
 }
 
 
@@ -37,8 +34,8 @@ int CustomXIOErrorHandler (Display* dsp)
     return 0;
     return 0;
 }
 }
 
 
-CX11Output::CX11Output (CApplicationContext& context, CVideoDriver& driver) :
-    COutput (context),
+CX11Output::CX11Output (CApplicationContext& context, CVideoDriver& driver, Detectors::CFullScreenDetector& detector) :
+    COutput (context, detector),
     m_driver (driver)
     m_driver (driver)
 {
 {
     // do not use previous handler, it might stop the app under weird circumstances
     // do not use previous handler, it might stop the app under weird circumstances
@@ -59,6 +56,8 @@ void CX11Output::reset ()
     this->free ();
     this->free ();
     // re-load screen info
     // re-load screen info
     this->loadScreenInfo ();
     this->loadScreenInfo ();
+    // do the same for the detector
+    this->m_detector.reset ();
 }
 }
 
 
 void CX11Output::free ()
 void CX11Output::free ()
@@ -187,46 +186,7 @@ void CX11Output::updateRender () const
     XClearWindow(this->m_display, this->m_root);
     XClearWindow(this->m_display, this->m_root);
     XFlush(this->m_display);
     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
+    // check for fullscreen windows and wait until there's none fullscreen
+    while (this->m_detector.anythingFullscreen () && this->m_context.state.general.keepRunning)
         usleep (FULLSCREEN_CHECK_WAIT_TIME);
         usleep (FULLSCREEN_CHECK_WAIT_TIME);
-    }
-    while (isFullscreen && this->m_context.state.general.keepRunning);
 }
 }

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

@@ -14,7 +14,7 @@ namespace WallpaperEngine::Render::Drivers::Output
     class CX11Output : public COutput
     class CX11Output : public COutput
     {
     {
     public:
     public:
-        CX11Output (CApplicationContext& context, CVideoDriver& driver);
+        CX11Output (CApplicationContext& context, CVideoDriver& driver, Detectors::CFullScreenDetector& detector);
         ~CX11Output ();
         ~CX11Output ();
 
 
         void reset () override;
         void reset () override;

+ 5 - 0
src/WallpaperEngine/Render/Helpers/CContextAware.cpp

@@ -7,6 +7,11 @@ namespace WallpaperEngine::Render::Helpers
     {
     {
     }
     }
 
 
+    CContextAware::CContextAware (CContextAware* from) :
+        CContextAware (from->getContext ())
+    {
+    }
+
     CContextAware::CContextAware (CRenderContext& context) :
     CContextAware::CContextAware (CRenderContext& context) :
         m_context (context)
         m_context (context)
     {
     {

+ 4 - 0
src/WallpaperEngine/Render/Helpers/CContextAware.h

@@ -17,6 +17,10 @@ namespace WallpaperEngine::Render
              * @param from Object to get the render context from
              * @param from Object to get the render context from
              */
              */
             CContextAware (CContextAware& from);
             CContextAware (CContextAware& from);
+            /**
+             * @param from Object to get the render context from
+             */
+            explicit CContextAware (CContextAware* from);
             explicit CContextAware (CRenderContext& context);
             explicit CContextAware (CRenderContext& context);
 
 
             /**
             /**

+ 1 - 1
src/WallpaperEngine/Render/Objects/CImage.cpp

@@ -81,7 +81,7 @@ CImage::CImage (CScene* scene, Core::Objects::CImage* image) :
         else
         else
         {
         {
             // get the first texture on the first pass (this one represents the image assigned to this object)
             // get the first texture on the first pass (this one represents the image assigned to this object)
-            this->m_texture = this->getScene ()->getContext ().resolveTexture (textureName);
+            this->m_texture = this->getContext ().resolveTexture (textureName);
         }
         }
     }
     }
     else
     else

+ 1 - 1
src/WallpaperEngine/Render/Objects/CSound.cpp

@@ -8,7 +8,7 @@ CSound::CSound (CScene* scene, Core::Objects::CSound* sound) :
     CObject (scene, Type, sound),
     CObject (scene, Type, sound),
     m_sound (sound)
     m_sound (sound)
 {
 {
-    if (this->getScene ()->getContext ().getApp ().getContext ().settings.audio.enabled)
+    if (this->getContext ().getApp ().getContext ().settings.audio.enabled)
         this->load ();
         this->load ();
 }
 }
 
 

+ 1 - 0
src/WallpaperEngine/Render/Objects/Effects/CMaterial.cpp

@@ -5,6 +5,7 @@ using namespace WallpaperEngine::Render::Objects;
 using namespace WallpaperEngine::Render::Objects::Effects;
 using namespace WallpaperEngine::Render::Objects::Effects;
 
 
 CMaterial::CMaterial (const Render::Objects::CEffect* effect, const Core::Objects::Images::CMaterial* material) :
 CMaterial::CMaterial (const Render::Objects::CEffect* effect, const Core::Objects::Images::CMaterial* material) :
+    Helpers::CContextAware (effect->getImage ()),
     m_effect (effect),
     m_effect (effect),
     m_material (material)
     m_material (material)
 {
 {

+ 7 - 5
src/WallpaperEngine/Render/Objects/Effects/CMaterial.h

@@ -6,6 +6,8 @@
 #include "WallpaperEngine/Render/Objects/Effects/CPass.h"
 #include "WallpaperEngine/Render/Objects/Effects/CPass.h"
 #include "WallpaperEngine/Render/Objects/CEffect.h"
 #include "WallpaperEngine/Render/Objects/CEffect.h"
 
 
+#include "WallpaperEngine/Render/Helpers/CContextAware.h"
+
 #include "CPass.h"
 #include "CPass.h"
 
 
 using namespace WallpaperEngine;
 using namespace WallpaperEngine;
@@ -20,16 +22,16 @@ namespace WallpaperEngine::Render::Objects::Effects
 {
 {
     class CPass;
     class CPass;
 
 
-    class CMaterial
+    class CMaterial : public Helpers::CContextAware
     {
     {
         friend class CPass;
         friend class CPass;
     public:
     public:
         CMaterial (const Render::Objects::CEffect* effect, const Core::Objects::Images::CMaterial* material);
         CMaterial (const Render::Objects::CEffect* effect, const Core::Objects::Images::CMaterial* material);
 
 
-        const std::vector<CPass*>& getPasses () const;
-        CImage* getImage () const;
-        const Core::Objects::Images::CMaterial* getMaterial () const;
-        const CEffect* getEffect () const;
+        [[nodiscard]] const std::vector<CPass*>& getPasses () const;
+        [[nodiscard]] CImage* getImage () const;
+        [[nodiscard]] const Core::Objects::Images::CMaterial* getMaterial () const;
+        [[nodiscard]] const CEffect* getEffect () const;
 
 
     private:
     private:
         void generatePasses ();
         void generatePasses ();

+ 5 - 4
src/WallpaperEngine/Render/Objects/Effects/CPass.cpp

@@ -23,6 +23,7 @@ using namespace WallpaperEngine::Render::Objects::Effects;
 extern float g_Time;
 extern float g_Time;
 
 
 CPass::CPass (CMaterial* material, Core::Objects::Images::Materials::CPass* pass) :
 CPass::CPass (CMaterial* material, Core::Objects::Images::Materials::CPass* pass) :
+    Helpers::CContextAware (material),
     m_material (material),
     m_material (material),
     m_pass (pass)
     m_pass (pass)
 {
 {
@@ -132,7 +133,7 @@ void CPass::render ()
     if (texture->isAnimated ())
     if (texture->isAnimated ())
     {
     {
         // calculate current texture and frame
         // calculate current texture and frame
-        double currentRenderTime = fmod (static_cast <double> (this->getMaterial ()->getImage ()->getScene ()->getContext ().getDriver ().getRenderTime ()), this->m_material->getImage ()->getAnimationTime ());
+        double currentRenderTime = fmod (static_cast <double> (this->getContext ().getDriver ().getRenderTime ()), this->m_material->getImage ()->getAnimationTime ());
 
 
         for (const auto& frameCur : texture->getFrames ())
         for (const auto& frameCur : texture->getFrames ())
         {
         {
@@ -522,7 +523,7 @@ void CPass::setupUniforms ()
                             textureRef = this->getMaterial ()->getImage ()->getScene ()->findFBO (textureName);
                             textureRef = this->getMaterial ()->getImage ()->getScene ()->findFBO (textureName);
                     }
                     }
                     else
                     else
-                        textureRef = this->getMaterial ()->getImage ()->getScene ()->getContext ().resolveTexture (textureName);
+                        textureRef = this->getContext ().resolveTexture (textureName);
 
 
                     this->m_finalTextures.insert (std::make_pair ((*fragCur).first, textureRef));
                     this->m_finalTextures.insert (std::make_pair ((*fragCur).first, textureRef));
                 }
                 }
@@ -551,7 +552,7 @@ void CPass::setupUniforms ()
                             textureRef = this->getMaterial ()->getImage ()->getScene ()->findFBO (textureName);
                             textureRef = this->getMaterial ()->getImage ()->getScene ()->findFBO (textureName);
                     }
                     }
                     else
                     else
-                        textureRef = this->getMaterial ()->getImage ()->getScene ()->getContext ().resolveTexture (textureName);
+                        textureRef = this->getContext ().resolveTexture (textureName);
 
 
                     this->m_finalTextures.insert (std::make_pair ((*vertCur).first, textureRef));
                     this->m_finalTextures.insert (std::make_pair ((*vertCur).first, textureRef));
                 }
                 }
@@ -695,7 +696,7 @@ void CPass::setupTextures ()
             else
             else
             {
             {
                 this->m_textures.emplace_back (
                 this->m_textures.emplace_back (
-                    this->m_material->getImage ()->getScene ()->getContext ().resolveTexture ((*cur))
+                    this->m_material->getImage ()->getContext ().resolveTexture ((*cur))
                 );
                 );
             }
             }
         }
         }

+ 3 - 1
src/WallpaperEngine/Render/Objects/Effects/CPass.h

@@ -10,6 +10,8 @@
 #include "WallpaperEngine/Assets/ITexture.h"
 #include "WallpaperEngine/Assets/ITexture.h"
 #include "WallpaperEngine/Render/CFBO.h"
 #include "WallpaperEngine/Render/CFBO.h"
 
 
+#include "WallpaperEngine/Render/Helpers/CContextAware.h"
+
 namespace WallpaperEngine::Render::Objects::Effects
 namespace WallpaperEngine::Render::Objects::Effects
 {
 {
     using namespace WallpaperEngine::Assets;
     using namespace WallpaperEngine::Assets;
@@ -18,7 +20,7 @@ namespace WallpaperEngine::Render::Objects::Effects
 
 
     class CMaterial;
     class CMaterial;
 
 
-    class CPass
+    class CPass : public Helpers::CContextAware
     {
     {
     public:
     public:
         CPass (CMaterial* material, Core::Objects::Images::Materials::CPass* pass);
         CPass (CMaterial* material, Core::Objects::Images::Materials::CPass* pass);