File indexing completed on 2024-12-08 13:21:45

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2011 Arthur Arlt <a.arlt@stud.uni-heidelberg.de>
0006     SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #pragma once
0011 
0012 #include <kwinglobals.h>
0013 
0014 #include <QObject>
0015 #include <QRegion>
0016 #include <QTimer>
0017 #include <memory>
0018 
0019 namespace KWin
0020 {
0021 
0022 class Output;
0023 class CompositorSelectionOwner;
0024 class CursorScene;
0025 class CursorView;
0026 class RenderBackend;
0027 class RenderLayer;
0028 class RenderLoop;
0029 class RenderTarget;
0030 class WorkspaceScene;
0031 class Window;
0032 class X11Window;
0033 class X11SyncManager;
0034 
0035 class KWIN_EXPORT Compositor : public QObject
0036 {
0037     Q_OBJECT
0038 public:
0039     enum class State {
0040         On = 0,
0041         Off,
0042         Starting,
0043         Stopping
0044     };
0045 
0046     ~Compositor() override;
0047     static Compositor *self();
0048 
0049     /**
0050      * Schedules a new repaint if no repaint is currently scheduled.
0051      */
0052     void scheduleRepaint();
0053 
0054     /**
0055      * Toggles compositing, that is if the Compositor is suspended it will be resumed
0056      * and if the Compositor is active it will be suspended.
0057      * Invoked by keybinding (shortcut default: Shift + Alt + F12).
0058      */
0059     virtual void toggleCompositing() = 0;
0060 
0061     /**
0062      * Re-initializes the Compositor completely.
0063      * Connected to the D-Bus signal org.kde.KWin /KWin reinitCompositing
0064      */
0065     virtual void reinitialize();
0066 
0067     /**
0068      * Whether the Compositor is active. That is a Scene is present and the Compositor is
0069      * not shutting down itself.
0070      */
0071     bool isActive();
0072 
0073     WorkspaceScene *scene() const
0074     {
0075         return m_scene.get();
0076     }
0077     CursorScene *cursorScene() const
0078     {
0079         return m_cursorScene.get();
0080     }
0081     RenderBackend *backend() const
0082     {
0083         return m_backend.get();
0084     }
0085 
0086     /**
0087      * @brief Static check to test whether the Compositor is available and active.
0088      *
0089      * @return bool @c true if there is a Compositor and it is active, @c false otherwise
0090      */
0091     static bool compositing()
0092     {
0093         return s_compositor != nullptr && s_compositor->isActive();
0094     }
0095 
0096     // for delayed supportproperty management of effects
0097     void keepSupportProperty(xcb_atom_t atom);
0098     void removeSupportProperty(xcb_atom_t atom);
0099 
0100     /**
0101      * Whether Compositing is possible in the Platform.
0102      * Returning @c false in this method makes only sense if requiresCompositing returns @c false.
0103      *
0104      * The default implementation returns @c true.
0105      * @see requiresCompositing
0106      */
0107     virtual bool compositingPossible() const;
0108     /**
0109      * Returns a user facing text explaining why compositing is not possible in case
0110      * compositingPossible returns @c false.
0111      *
0112      * The default implementation returns an empty string.
0113      * @see compositingPossible
0114      */
0115     virtual QString compositingNotPossibleReason() const;
0116     /**
0117      * Whether OpenGL compositing is broken.
0118      * The Platform can implement this method if it is able to detect whether OpenGL compositing
0119      * broke (e.g. triggered a crash in a previous run).
0120      *
0121      * Default implementation returns @c false.
0122      * @see createOpenGLSafePoint
0123      */
0124     virtual bool openGLCompositingIsBroken() const;
0125     enum class OpenGLSafePoint {
0126         PreInit,
0127         PostInit,
0128         PreFrame,
0129         PostFrame,
0130         PostLastGuardedFrame
0131     };
0132     /**
0133      * This method is invoked before and after creating the OpenGL rendering Scene.
0134      * An implementing Platform can use it to detect crashes triggered by the OpenGL implementation.
0135      * This can be used for openGLCompositingIsBroken.
0136      *
0137      * The default implementation does nothing.
0138      * @see openGLCompositingIsBroken.
0139      */
0140     virtual void createOpenGLSafePoint(OpenGLSafePoint safePoint);
0141 
0142 Q_SIGNALS:
0143     void compositingToggled(bool active);
0144     void aboutToDestroy();
0145     void aboutToToggleCompositing();
0146     void sceneCreated();
0147 
0148 protected:
0149     explicit Compositor(QObject *parent = nullptr);
0150 
0151     virtual void start() = 0;
0152     virtual void stop();
0153 
0154     /**
0155      * @brief Prepares start.
0156      * @return bool @c true if start should be continued and @c if not.
0157      */
0158     bool setupStart();
0159     /**
0160      * Continues the startup after Scene And Workspace are created
0161      */
0162     void startupWithWorkspace();
0163 
0164     virtual void configChanged();
0165 
0166     void destroyCompositorSelection();
0167 
0168     static Compositor *s_compositor;
0169 
0170 protected Q_SLOTS:
0171     virtual void composite(RenderLoop *renderLoop);
0172 
0173 private Q_SLOTS:
0174     void handleFrameRequested(RenderLoop *renderLoop);
0175 
0176 private:
0177     void initializeX11();
0178     void cleanupX11();
0179 
0180     void releaseCompositorSelection();
0181     void deleteUnusedSupportProperties();
0182 
0183     bool attemptOpenGLCompositing();
0184     bool attemptQPainterCompositing();
0185 
0186     Output *findOutput(RenderLoop *loop) const;
0187     void addOutput(Output *output);
0188     void removeOutput(Output *output);
0189 
0190     void addSuperLayer(RenderLayer *layer);
0191     void removeSuperLayer(RenderLayer *layer);
0192 
0193     void prePaintPass(RenderLayer *layer);
0194     void postPaintPass(RenderLayer *layer);
0195     void preparePaintPass(RenderLayer *layer, QRegion *repaint);
0196     void paintPass(RenderLayer *layer, RenderTarget *target, const QRegion &region);
0197 
0198     State m_state = State::Off;
0199     std::unique_ptr<CompositorSelectionOwner> m_selectionOwner;
0200     QTimer m_releaseSelectionTimer;
0201     QList<xcb_atom_t> m_unusedSupportProperties;
0202     QTimer m_unusedSupportPropertyTimer;
0203     std::unique_ptr<WorkspaceScene> m_scene;
0204     std::unique_ptr<CursorScene> m_cursorScene;
0205     std::unique_ptr<RenderBackend> m_backend;
0206     QHash<RenderLoop *, RenderLayer *> m_superlayers;
0207     CompositingType m_selectedCompositor = NoCompositing;
0208 };
0209 
0210 class KWIN_EXPORT WaylandCompositor final : public Compositor
0211 {
0212     Q_OBJECT
0213 public:
0214     static WaylandCompositor *create(QObject *parent = nullptr);
0215     ~WaylandCompositor() override;
0216 
0217     void toggleCompositing() override;
0218 
0219 protected:
0220     void start() override;
0221 
0222 private:
0223     explicit WaylandCompositor(QObject *parent);
0224 };
0225 
0226 class KWIN_EXPORT X11Compositor final : public Compositor
0227 {
0228     Q_OBJECT
0229 public:
0230     enum SuspendReason {
0231         NoReasonSuspend = 0,
0232         UserSuspend = 1 << 0,
0233         BlockRuleSuspend = 1 << 1,
0234         ScriptSuspend = 1 << 2,
0235         AllReasonSuspend = 0xff
0236     };
0237     Q_DECLARE_FLAGS(SuspendReasons, SuspendReason)
0238     Q_ENUM(SuspendReason)
0239     Q_FLAG(SuspendReasons)
0240 
0241     static X11Compositor *create(QObject *parent = nullptr);
0242     ~X11Compositor() override;
0243 
0244     X11SyncManager *syncManager() const;
0245 
0246     /**
0247      * @brief Suspends the Compositor if it is currently active.
0248      *
0249      * Note: it is possible that the Compositor is not able to suspend. Use isActive to check
0250      * whether the Compositor has been suspended.
0251      *
0252      * @return void
0253      * @see resume
0254      * @see isActive
0255      */
0256     void suspend(SuspendReason reason);
0257 
0258     /**
0259      * @brief Resumes the Compositor if it is currently suspended.
0260      *
0261      * Note: it is possible that the Compositor cannot be resumed, that is there might be Clients
0262      * blocking the usage of Compositing or the Scene might be broken. Use isActive to check
0263      * whether the Compositor has been resumed. Also check isCompositingPossible and
0264      * isOpenGLBroken.
0265      *
0266      * Note: The starting of the Compositor can require some time and is partially done threaded.
0267      * After this method returns the setup may not have been completed.
0268      *
0269      * @return void
0270      * @see suspend
0271      * @see isActive
0272      * @see isCompositingPossible
0273      * @see isOpenGLBroken
0274      */
0275     void resume(SuspendReason reason);
0276 
0277     void toggleCompositing() override;
0278     void reinitialize() override;
0279     void configChanged() override;
0280     bool compositingPossible() const override;
0281     QString compositingNotPossibleReason() const override;
0282     bool openGLCompositingIsBroken() const override;
0283     void createOpenGLSafePoint(OpenGLSafePoint safePoint) override;
0284 
0285     /**
0286      * Checks whether @p w is the Scene's overlay window.
0287      */
0288     bool checkForOverlayWindow(WId w) const;
0289 
0290     /**
0291      * @returns Whether the Scene's Overlay X Window is visible.
0292      */
0293     bool isOverlayWindowVisible() const;
0294 
0295     void updateClientCompositeBlocking(X11Window *client = nullptr);
0296 
0297     static X11Compositor *self();
0298 
0299 protected:
0300     void start() override;
0301     void stop() override;
0302     void composite(RenderLoop *renderLoop) override;
0303 
0304 private:
0305     explicit X11Compositor(QObject *parent);
0306 
0307     std::unique_ptr<QThread> m_openGLFreezeProtectionThread;
0308     std::unique_ptr<QTimer> m_openGLFreezeProtection;
0309     std::unique_ptr<X11SyncManager> m_syncManager;
0310     /**
0311      * Whether the Compositor is currently suspended, 8 bits encoding the reason
0312      */
0313     SuspendReasons m_suspended;
0314     int m_framesToTestForSafety = 3;
0315 };
0316 
0317 }