diff --git a/autotests/integration/kwin_wayland_test.cpp b/autotests/integration/kwin_wayland_test.cpp --- a/autotests/integration/kwin_wayland_test.cpp +++ b/autotests/integration/kwin_wayland_test.cpp @@ -126,7 +126,7 @@ { disconnect(kwinApp()->platform(), &Platform::screensQueried, this, &WaylandTestApplication::continueStartupWithScreens); createScreens(); - createCompositor(); + WaylandCompositor::create(); connect(Compositor::self(), &Compositor::sceneCreated, this, &WaylandTestApplication::continueStartupWithScene); } diff --git a/composite.h b/composite.h --- a/composite.h +++ b/composite.h @@ -38,23 +38,15 @@ { Q_OBJECT public: - enum SuspendReason { - NoReasonSuspend = 0, - UserSuspend = 1 << 0, - BlockRuleSuspend = 1 << 1, - ScriptSuspend = 1 << 2, - AllReasonSuspend = 0xff - }; - Q_DECLARE_FLAGS(SuspendReasons, SuspendReason) - enum class State { On = 0, Off, Starting, Stopping }; ~Compositor() override; + static Compositor *self(); // when adding repaints caused by a window, you probably want to use // either Toplevel::addRepaint() or Toplevel::addWorkspaceRepaint() @@ -80,75 +72,37 @@ */ void bufferSwapComplete(); - /** - * @brief Suspends the Compositor if it is currently active. - * - * Note: it is possible that the Compositor is not able to suspend. Use isActive to check - * whether the Compositor has been suspended. - * - * @return void - * @see resume - * @see isActive - */ - Q_INVOKABLE void suspend(Compositor::SuspendReason reason); - - /** - * @brief Resumes the Compositor if it is currently suspended. - * - * Note: it is possible that the Compositor cannot be resumed, that is there might be Clients - * blocking the usage of Compositing or the Scene might be broken. Use isActive to check - * whether the Compositor has been resumed. Also check isCompositingPossible and - * isOpenGLBroken. - * - * Note: The starting of the Compositor can require some time and is partially done threaded. - * After this method returns the setup may not have been completed. - * - * @return void - * @see suspend - * @see isActive - * @see isCompositingPossible - * @see isOpenGLBroken - */ - Q_INVOKABLE void resume(Compositor::SuspendReason reason); - /** * Toggles compositing, that is if the Compositor is suspended it will be resumed * and if the Compositor is active it will be suspended. * Invoked by keybinding (shortcut default: Shift + Alt + F12). */ - void toggleCompositing(); + virtual void toggleCompositing() = 0; /** * Re-initializes the Compositor completely. * Connected to the D-Bus signal org.kde.KWin /KWin reinitCompositing */ - void reinitialize(); + virtual void reinitialize(); /** * Whether the Compositor is active. That is a Scene is present and the Compositor is * not shutting down itself. */ bool isActive(); - int xrrRefreshRate() const { - return m_xrrRefreshRate; - } + virtual int refreshRate() const = 0; bool hasScene() const { return m_scene != NULL; } + Scene *scene() const { + return m_scene; + } /** * Checks whether @p w is the Scene's overlay window. */ - bool checkForOverlayWindow(WId w) const; - /** - * @returns Whether the Scene's Overlay X Window is visible. - */ - bool isOverlayWindowVisible() const; - - Scene *scene() { - return m_scene; - } + virtual bool checkForOverlayWindow(WId w) const = 0; /** * @brief Static check to test whether the Compositor is available and active. @@ -159,8 +113,9 @@ return s_compositor != NULL && s_compositor->isActive(); } - void updateCompositeBlocking(); - void updateClientCompositeBlocking(KWin::Client* c); + + virtual void updateCompositeBlocking() = 0; + virtual void updateClientCompositeBlocking(KWin::Client *c) = 0; // for delayed supportproperty management of effects void keepSupportProperty(xcb_atom_t atom); @@ -174,42 +129,48 @@ void bufferSwapCompleted(); protected: + explicit Compositor(QObject *parent = nullptr); void timerEvent(QTimerEvent *te) override; -private: - Q_INVOKABLE void start(); + virtual void start() = 0; void stop(); - void claimCompositorSelection(); - + /** + * @brief Prepares start. + * @return bool @c true if start should be continued and @c if not. + */ + bool setupStart(); /** * Continues the startup after Scene And Workspace are created */ void startupWithWorkspace(); + virtual void performCompositing(); + + virtual void configChanged(); + + void destroyCompositorSelection(); + + static Compositor *s_compositor; + +private: + void claimCompositorSelection(); + void setupX11Support(); void setCompositeTimer(); - void performCompositing(); bool windowRepaintsPending() const; void releaseCompositorSelection(); void deleteUnusedSupportProperties(); - void slotConfigChanged(); - State m_state; - /** - * Whether the Compositor is currently suspended, 8 bits encoding the reason - */ - SuspendReasons m_suspended; QBasicTimer compositeTimer; CompositorSelectionOwner *m_selectionOwner; QTimer m_releaseSelectionTimer; QList m_unusedSupportProperties; QTimer m_unusedSupportPropertyTimer; qint64 vBlankInterval, fpsInterval; - int m_xrrRefreshRate; QRegion repaints_region; qint64 m_timeSinceLastVBlank; @@ -221,8 +182,106 @@ int m_framesToTestForSafety = 3; QElapsedTimer m_monotonicClock; +}; - KWIN_SINGLETON_VARIABLE(Compositor, s_compositor) +class KWIN_EXPORT WaylandCompositor : public Compositor +{ + Q_OBJECT +public: + static WaylandCompositor *create(QObject *parent = nullptr); + ~WaylandCompositor() override = default; + + int refreshRate() const override; + + void toggleCompositing() override; + + bool checkForOverlayWindow(WId w) const override; + + void updateCompositeBlocking() override; + void updateClientCompositeBlocking(KWin::Client* c) override; + +protected: + void start() override; + +private: + explicit WaylandCompositor(QObject *parent); +}; + +class KWIN_EXPORT X11Compositor : public Compositor +{ + Q_OBJECT +public: + enum SuspendReason { + NoReasonSuspend = 0, + UserSuspend = 1 << 0, + BlockRuleSuspend = 1 << 1, + ScriptSuspend = 1 << 2, + AllReasonSuspend = 0xff + }; + Q_DECLARE_FLAGS(SuspendReasons, SuspendReason) + + static X11Compositor *create(QObject *parent = nullptr); + ~X11Compositor() override = default; + + /** + * @brief Suspends the Compositor if it is currently active. + * + * Note: it is possible that the Compositor is not able to suspend. Use isActive to check + * whether the Compositor has been suspended. + * + * @return void + * @see resume + * @see isActive + **/ + Q_INVOKABLE void suspend(SuspendReason reason); + + /** + * @brief Resumes the Compositor if it is currently suspended. + * + * Note: it is possible that the Compositor cannot be resumed, that is there might be Clients + * blocking the usage of Compositing or the Scene might be broken. Use isActive to check + * whether the Compositor has been resumed. Also check isCompositingPossible and + * isOpenGLBroken. + * + * Note: The starting of the Compositor can require some time and is partially done threaded. + * After this method returns the setup may not have been completed. + * + * @return void + * @see suspend + * @see isActive + * @see isCompositingPossible + * @see isOpenGLBroken + **/ + Q_INVOKABLE void resume(SuspendReason reason); + + void toggleCompositing() override; + void reinitialize() override; + + void configChanged() override; + + bool checkForOverlayWindow(WId w) const override; + /** + * @returns Whether the Scene's Overlay X Window is visible. + **/ + bool isOverlayWindowVisible() const; + + int refreshRate() const override; + + void updateCompositeBlocking() override; + void updateClientCompositeBlocking(KWin::Client* c) override; + +protected: + void start() override; + void performCompositing() override; + +private: + explicit X11Compositor(QObject *parent); + /** + * Whether the Compositor is currently suspended, 8 bits encoding the reason + **/ + SuspendReasons m_suspended; + + int m_xrrRefreshRate; }; } diff --git a/composite.cpp b/composite.cpp --- a/composite.cpp +++ b/composite.cpp @@ -62,15 +62,36 @@ #include -Q_DECLARE_METATYPE(KWin::Compositor::SuspendReason) +Q_DECLARE_METATYPE(KWin::X11Compositor::SuspendReason) namespace KWin { extern int screen_number; // main.cpp extern bool is_multihead; extern int currentRefreshRate(); +Compositor *Compositor::s_compositor = nullptr; +Compositor *Compositor::self() +{ + return s_compositor; +} + +WaylandCompositor *WaylandCompositor::create(QObject *parent) +{ + Q_ASSERT(!s_compositor); + auto *compositor = new WaylandCompositor(parent); + s_compositor = compositor; + return compositor; +} +X11Compositor *X11Compositor::create(QObject *parent) +{ + Q_ASSERT(!s_compositor); + auto *compositor = new X11Compositor(parent); + s_compositor = compositor; + return compositor; +} + class CompositorSelectionOwner : public KSelectionOwner { Q_OBJECT @@ -92,26 +113,21 @@ bool m_owning; }; -KWIN_SINGLETON_FACTORY_VARIABLE(Compositor, s_compositor) - static inline qint64 milliToNano(int milli) { return qint64(milli) * 1000 * 1000; } static inline qint64 nanoToMilli(int nano) { return nano / (1000*1000); } Compositor::Compositor(QObject* workspace) : QObject(workspace) , m_state(State::Off) - , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) , m_selectionOwner(NULL) , vBlankInterval(0) , fpsInterval(0) - , m_xrrRefreshRate(0) , m_timeSinceLastVBlank(0) , m_scene(NULL) , m_bufferSwapPending(false) , m_composeAtSwapCompletion(false) { - qRegisterMetaType("Compositor::SuspendReason"); - connect(options, &Options::configChanged, this, &Compositor::slotConfigChanged); + connect(options, &Options::configChanged, this, &Compositor::configChanged); m_monotonicClock.start(); @@ -131,7 +147,7 @@ // Workspace is completely constructed, so calling Workspace::self() would result // in undefined behavior. This is fixed by using a delayed invocation. if (kwinApp()->platform()->isReady()) { - QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); + QTimer::singleShot(0, this, &Compositor::start); } connect(kwinApp()->platform(), &Platform::readyChanged, this, [this] (bool ready) { @@ -142,12 +158,6 @@ } }, Qt::QueuedConnection ); - connect(kwinApp(), &Application::x11ConnectionAboutToBeDestroyed, this, - [this] { - delete m_selectionOwner; - m_selectionOwner = nullptr; - } - ); if (qEnvironmentVariableIsSet("KWIN_MAX_FRAMES_TESTED")) m_framesToTestForSafety = qEnvironmentVariableIntValue("KWIN_MAX_FRAMES_TESTED"); @@ -161,35 +171,18 @@ emit aboutToDestroy(); stop(); deleteUnusedSupportProperties(); - delete m_selectionOwner; + destroyCompositorSelection(); s_compositor = NULL; } -void Compositor::start() +bool Compositor::setupStart() { if (kwinApp()->isTerminating()) { // Don't start while KWin is terminating. An event to restart might be lingering in the event queue due to graphics reset. - return; + return false; } if (m_state != State::Off) { - return; - } - if (m_suspended) { - QStringList reasons; - if (m_suspended & UserSuspend) { - reasons << QStringLiteral("Disabled by User"); - } - if (m_suspended & BlockRuleSuspend) { - reasons << QStringLiteral("Disabled by Window"); - } - if (m_suspended & ScriptSuspend) { - reasons << QStringLiteral("Disabled by Script"); - } - qCDebug(KWIN_CORE) << "Compositing is suspended, reason:" << reasons; - return; - } else if (!kwinApp()->platform()->compositingPossible()) { - qCCritical(KWIN_CORE) << "Compositing is not possible"; - return; + return false; } m_state = State::Starting; @@ -262,7 +255,7 @@ qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken"; qApp->quit(); } - return; + return false; } kwinApp()->platform()->setSelectedCompositor(m_scene->compositingType() & OpenGLCompositing ? OpenGLCompositing : m_scene->compositingType()); @@ -275,11 +268,7 @@ connect(m_scene, &Scene::resetCompositing, this, &Compositor::reinitialize); emit sceneCreated(); - if (Workspace::self()) { - startupWithWorkspace(); - } else { - connect(kwinApp(), &Application::workspaceCreated, this, &Compositor::startupWithWorkspace); - } + return true; } void Compositor::claimCompositorSelection() @@ -319,10 +308,9 @@ Q_ASSERT(m_scene); connect(workspace(), &Workspace::destroyed, this, [this] { compositeTimer.stop(); }); setupX11Support(); - m_xrrRefreshRate = KWin::currentRefreshRate(); fpsInterval = options->maxFpsInterval(); if (m_scene->syncsToVBlank()) { // if we do vsync, set the fps to the next multiple of the vblank rate - vBlankInterval = milliToNano(1000) / m_xrrRefreshRate; + vBlankInterval = milliToNano(1000) / currentRefreshRate(); fpsInterval = qMax((fpsInterval / vBlankInterval) * vBlankInterval, vBlankInterval); } else vBlankInterval = milliToNano(1); // no sync - DO NOT set "0", would cause div-by-zero segfaults. @@ -431,6 +419,12 @@ emit compositingToggled(false); } +void Compositor::destroyCompositorSelection() +{ + delete m_selectionOwner; + m_selectionOwner = nullptr; +} + void Compositor::releaseCompositorSelection() { switch (m_state) { @@ -479,16 +473,14 @@ } } -void Compositor::slotConfigChanged() +void Compositor::configChanged() { - if (!m_suspended) { - start(); - if (effects) // setupCompositing() may fail - effects->reconfigure(); - addRepaintFull(); - } else { - stop(); + reinitialize(); + if (effects) { + // setupCompositing() might fail. + effects->reconfigure(); } + addRepaintFull(); } void Compositor::reinitialize() @@ -498,86 +490,13 @@ // Restart compositing stop(); - // resume compositing if suspended - m_suspended = NoReasonSuspend; start(); if (effects) { // start() may fail effects->reconfigure(); } } -// for the shortcut -void Compositor::toggleCompositing() -{ - if (kwinApp()->platform()->requiresCompositing()) { - // we are not allowed to turn on/off compositing - return; - } - if (m_suspended) { // direct user call; clear all bits - resume(AllReasonSuspend); - } else { // but only set the user one (sufficient to suspend) - suspend(UserSuspend); - } -} - -void Compositor::updateCompositeBlocking() -{ - updateClientCompositeBlocking(NULL); -} - -void Compositor::updateClientCompositeBlocking(Client *c) -{ - if (kwinApp()->platform()->requiresCompositing()) { - return; - } - if (c) { // if c == 0 we just check if we can resume - if (c->isBlockingCompositing()) { - if (!(m_suspended & BlockRuleSuspend)) // do NOT attempt to call suspend(true); from within the eventchain! - QMetaObject::invokeMethod(this, "suspend", Qt::QueuedConnection, Q_ARG(Compositor::SuspendReason, BlockRuleSuspend)); - } - } - else if (m_suspended & BlockRuleSuspend) { // lost a client and we're blocked - can we resume? - bool resume = true; - for (ClientList::ConstIterator it = Workspace::self()->clientList().constBegin(); it != Workspace::self()->clientList().constEnd(); ++it) { - if ((*it)->isBlockingCompositing()) { - resume = false; - break; - } - } - if (resume) { // do NOT attempt to call suspend(false); from within the eventchain! - QMetaObject::invokeMethod(this, "resume", Qt::QueuedConnection, Q_ARG(Compositor::SuspendReason, BlockRuleSuspend)); - } - } -} - -void Compositor::suspend(Compositor::SuspendReason reason) -{ - if (kwinApp()->platform()->requiresCompositing()) { - return; - } - Q_ASSERT(reason != NoReasonSuspend); - m_suspended |= reason; - if (reason & KWin::Compositor::ScriptSuspend) { - // when disabled show a shortcut how the user can get back compositing - const auto shortcuts = KGlobalAccel::self()->shortcut(workspace()->findChild(QStringLiteral("Suspend Compositing"))); - if (!shortcuts.isEmpty()) { - // display notification only if there is the shortcut - const QString message = i18n("Desktop effects have been suspended by another application.
" - "You can resume using the '%1' shortcut.", shortcuts.first().toString(QKeySequence::NativeText)); - KNotification::event(QStringLiteral("compositingsuspendeddbus"), message); - } - } - stop(); -} - -void Compositor::resume(Compositor::SuspendReason reason) -{ - Q_ASSERT(reason != NoReasonSuspend); - m_suspended &= ~reason; - start(); -} - void Compositor::addRepaint(int x, int y, int w, int h) { if (!hasScene()) @@ -641,9 +560,6 @@ void Compositor::performCompositing() { - if (m_scene->usesOverlayWindow() && !isOverlayWindowVisible()) - return; // nothing is visible anyway - // If a buffer swap is still pending, we return to the event loop and // continue processing events until the swap has completed. if (m_bufferSwapPending) { @@ -875,29 +791,212 @@ return m_state == State::On; } -bool Compositor::checkForOverlayWindow(WId w) const +WaylandCompositor::WaylandCompositor(QObject *parent) + : Compositor(parent) +{ + connect(kwinApp(), &Application::x11ConnectionAboutToBeDestroyed, + this, &WaylandCompositor::destroyCompositorSelection); +} + +// for the shortcut +void WaylandCompositor::toggleCompositing() +{ + // Not possible on Wayland because we always composite. +} + +void WaylandCompositor::start() +{ + if (!Compositor::setupStart()) { + // Internal setup failed, abort. + return; + } + if (Workspace::self()) { + startupWithWorkspace(); + } else { + connect(kwinApp(), &Application::workspaceCreated, this, &WaylandCompositor::startupWithWorkspace); + } +} + +bool WaylandCompositor::checkForOverlayWindow(WId w) const +{ + Q_UNUSED(w) + // There is no overlay window in Wayland/XWayland. + return false; +} + +int WaylandCompositor::refreshRate() const +{ + // TODO: This makes no sense on Wayland. First step would be to atleast + // set the refresh rate to the highest available one. Second step + // would be to not use a uniform value at all but per screen. + return KWin::currentRefreshRate(); +} + +void WaylandCompositor::updateCompositeBlocking() +{ + // Composite blocking not possible on Wayland. +} + +void WaylandCompositor::updateClientCompositeBlocking(Client *c) +{ + Q_UNUSED(c) + // Composite blocking not possible on Wayland. +} + +X11Compositor::X11Compositor(QObject *parent) + : Compositor(parent) + , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) + , m_xrrRefreshRate(0) +{ + qRegisterMetaType("X11Compositor::SuspendReason"); +} + +// for the shortcut +void X11Compositor::toggleCompositing() +{ + if (kwinApp()->platform()->requiresCompositing()) { + // we are not allowed to turn on/off compositing + return; + } + if (m_suspended) { // direct user call; clear all bits + resume(AllReasonSuspend); + } else { // but only set the user one (sufficient to suspend) + suspend(UserSuspend); + } +} + +void X11Compositor::reinitialize() +{ + // resume compositing if suspended + m_suspended = NoReasonSuspend; + Compositor::reinitialize(); +} + +void X11Compositor::configChanged() +{ + if (m_suspended) { + stop(); + return; + } + Compositor::configChanged(); +} + +void X11Compositor::suspend(X11Compositor::SuspendReason reason) +{ + Q_ASSERT(reason != NoReasonSuspend); + m_suspended |= reason; + if (reason & ScriptSuspend) { + // when disabled show a shortcut how the user can get back compositing + const auto shortcuts = KGlobalAccel::self()->shortcut(workspace()->findChild(QStringLiteral("Suspend Compositing"))); + if (!shortcuts.isEmpty()) { + // display notification only if there is the shortcut + const QString message = i18n("Desktop effects have been suspended by another application.
" + "You can resume using the '%1' shortcut.", shortcuts.first().toString(QKeySequence::NativeText)); + KNotification::event(QStringLiteral("compositingsuspendeddbus"), message); + } + } + stop(); +} + +void X11Compositor::resume(X11Compositor::SuspendReason reason) +{ + Q_ASSERT(reason != NoReasonSuspend); + m_suspended &= ~reason; + start(); +} + +void X11Compositor::start() +{ + if (m_suspended) { + QStringList reasons; + if (m_suspended & UserSuspend) { + reasons << QStringLiteral("Disabled by User"); + } + if (m_suspended & BlockRuleSuspend) { + reasons << QStringLiteral("Disabled by Window"); + } + if (m_suspended & ScriptSuspend) { + reasons << QStringLiteral("Disabled by Script"); + } + qCDebug(KWIN_CORE) << "Compositing is suspended, reason:" << reasons; + return; + } else if (!kwinApp()->platform()->compositingPossible()) { + qCCritical(KWIN_CORE) << "Compositing is not possible"; + return; + } + if (!Compositor::setupStart()) { + // Internal setup failed, abort. + return; + } + m_xrrRefreshRate = KWin::currentRefreshRate(); + startupWithWorkspace(); +} +void X11Compositor::performCompositing() +{ + if (scene()->usesOverlayWindow() && !isOverlayWindowVisible()) { + return; // nothing is visible anyway + } + Compositor::performCompositing(); +} + +bool X11Compositor::checkForOverlayWindow(WId w) const { if (!hasScene()) { // no scene, so it cannot be the overlay window return false; } - if (!m_scene->overlayWindow()) { + if (!scene()->overlayWindow()) { // no overlay window, it cannot be the overlay return false; } // and compare the window ID's - return w == m_scene->overlayWindow()->window(); + return w == scene()->overlayWindow()->window(); } -bool Compositor::isOverlayWindowVisible() const +bool X11Compositor::isOverlayWindowVisible() const { if (!hasScene()) { return false; } - if (!m_scene->overlayWindow()) { + if (!scene()->overlayWindow()) { return false; } - return m_scene->overlayWindow()->isVisible(); + return scene()->overlayWindow()->isVisible(); +} + +int X11Compositor::refreshRate() const +{ + return m_xrrRefreshRate; +} + +void X11Compositor::updateCompositeBlocking() +{ + updateClientCompositeBlocking(NULL); +} + +void X11Compositor::updateClientCompositeBlocking(Client *c) +{ + if (kwinApp()->platform()->requiresCompositing()) { + return; + } + if (c) { // if c == 0 we just check if we can resume + if (c->isBlockingCompositing()) { + if (!(m_suspended & BlockRuleSuspend)) // do NOT attempt to call suspend(true); from within the eventchain! + QMetaObject::invokeMethod(this, "suspend", Qt::QueuedConnection, Q_ARG(SuspendReason, BlockRuleSuspend)); + } + } + else if (m_suspended & BlockRuleSuspend) { // lost a client and we're blocked - can we resume? + bool resume = true; + for (ClientList::ConstIterator it = Workspace::self()->clientList().constBegin(); it != Workspace::self()->clientList().constEnd(); ++it) { + if ((*it)->isBlockingCompositing()) { + resume = false; + break; + } + } + if (resume) { // do NOT attempt to call suspend(false); from within the eventchain! + QMetaObject::invokeMethod(this, "resume", Qt::QueuedConnection, Q_ARG(SuspendReason, BlockRuleSuspend)); + } + } } } // namespace diff --git a/dbusinterface.cpp b/dbusinterface.cpp --- a/dbusinterface.cpp +++ b/dbusinterface.cpp @@ -309,12 +309,16 @@ void CompositorDBusInterface::resume() { - m_compositor->resume(Compositor::ScriptSuspend); + if (kwinApp()->operationMode() == Application::OperationModeX11) { + static_cast(m_compositor)->resume(X11Compositor::ScriptSuspend); + } } void CompositorDBusInterface::suspend() { - m_compositor->suspend(Compositor::ScriptSuspend); + if (kwinApp()->operationMode() == Application::OperationModeX11) { + static_cast(m_compositor)->suspend(X11Compositor::ScriptSuspend); + } } void CompositorDBusInterface::reinitialize() diff --git a/main.h b/main.h --- a/main.h +++ b/main.h @@ -212,7 +212,6 @@ void createWorkspace(); void createAtoms(); void createOptions(); - void createCompositor(); void setupEventFilters(); void destroyWorkspace(); void destroyCompositor(); diff --git a/main.cpp b/main.cpp --- a/main.cpp +++ b/main.cpp @@ -310,11 +310,6 @@ options = new Options; } -void Application::createCompositor() -{ - Compositor::create(this); -} - void Application::setupEventFilters() { installNativeEventFilter(m_eventFilter.data()); diff --git a/main_wayland.cpp b/main_wayland.cpp --- a/main_wayland.cpp +++ b/main_wayland.cpp @@ -180,7 +180,7 @@ { disconnect(kwinApp()->platform(), &Platform::screensQueried, this, &ApplicationWayland::continueStartupWithScreens); createScreens(); - createCompositor(); + WaylandCompositor::create(); connect(Compositor::self(), &Compositor::sceneCreated, this, &ApplicationWayland::continueStartupWithScene); } diff --git a/platformsupport/scenes/opengl/backend.h b/platformsupport/scenes/opengl/backend.h --- a/platformsupport/scenes/opengl/backend.h +++ b/platformsupport/scenes/opengl/backend.h @@ -112,7 +112,7 @@ * * @return :OverlayWindow* */ - virtual OverlayWindow *overlayWindow(); + virtual OverlayWindow *overlayWindow() const; /** * @brief Whether the creation of the Backend failed. * diff --git a/platformsupport/scenes/opengl/backend.cpp b/platformsupport/scenes/opengl/backend.cpp --- a/platformsupport/scenes/opengl/backend.cpp +++ b/platformsupport/scenes/opengl/backend.cpp @@ -80,7 +80,7 @@ return region; } -OverlayWindow* OpenGLBackend::overlayWindow() +OverlayWindow* OpenGLBackend::overlayWindow() const { return NULL; } diff --git a/plugins/platforms/x11/common/eglonxbackend.h b/plugins/platforms/x11/common/eglonxbackend.h --- a/plugins/platforms/x11/common/eglonxbackend.h +++ b/plugins/platforms/x11/common/eglonxbackend.h @@ -40,7 +40,7 @@ SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override; QRegion prepareRenderingFrame() override; void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion) override; - OverlayWindow* overlayWindow() override; + OverlayWindow* overlayWindow() const override; bool usesOverlayWindow() const override; void init() override; diff --git a/plugins/platforms/x11/common/eglonxbackend.cpp b/plugins/platforms/x11/common/eglonxbackend.cpp --- a/plugins/platforms/x11/common/eglonxbackend.cpp +++ b/plugins/platforms/x11/common/eglonxbackend.cpp @@ -463,7 +463,7 @@ return m_usesOverlayWindow; } -OverlayWindow* EglOnXBackend::overlayWindow() +OverlayWindow* EglOnXBackend::overlayWindow() const { return m_overlayWindow; } diff --git a/plugins/platforms/x11/standalone/glxbackend.h b/plugins/platforms/x11/standalone/glxbackend.h --- a/plugins/platforms/x11/standalone/glxbackend.h +++ b/plugins/platforms/x11/standalone/glxbackend.h @@ -76,7 +76,7 @@ void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion) override; bool makeCurrent() override; void doneCurrent() override; - OverlayWindow* overlayWindow() override; + OverlayWindow* overlayWindow() const override; bool usesOverlayWindow() const override; void init() override; diff --git a/plugins/platforms/x11/standalone/glxbackend.cpp b/plugins/platforms/x11/standalone/glxbackend.cpp --- a/plugins/platforms/x11/standalone/glxbackend.cpp +++ b/plugins/platforms/x11/standalone/glxbackend.cpp @@ -849,7 +849,7 @@ glXMakeCurrent(display(), None, nullptr); } -OverlayWindow* GlxBackend::overlayWindow() +OverlayWindow* GlxBackend::overlayWindow() const { return m_overlayWindow; } diff --git a/plugins/platforms/x11/standalone/screens_xrandr.cpp b/plugins/platforms/x11/standalone/screens_xrandr.cpp --- a/plugins/platforms/x11/standalone/screens_xrandr.cpp +++ b/plugins/platforms/x11/standalone/screens_xrandr.cpp @@ -53,7 +53,7 @@ if (!workspace()->compositing()) { return; } - if (Compositor::self()->xrrRefreshRate() == Options::currentRefreshRate()) { + if (Compositor::self()->refreshRate() == Options::currentRefreshRate()) { return; } // desktopResized() should take care of when the size or diff --git a/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/scene_opengl.h --- a/plugins/scenes/opengl/scene_opengl.h +++ b/plugins/scenes/opengl/scene_opengl.h @@ -51,7 +51,7 @@ Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame) override; Shadow *createShadow(Toplevel *toplevel) override; void screenGeometryChanged(const QSize &size) override; - OverlayWindow *overlayWindow() override; + OverlayWindow *overlayWindow() const override; bool usesOverlayWindow() const override; bool blocksForRetrace() const override; bool syncsToVBlank() const override; diff --git a/plugins/scenes/opengl/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp --- a/plugins/scenes/opengl/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -519,7 +519,7 @@ return scene; } -OverlayWindow *SceneOpenGL::overlayWindow() +OverlayWindow *SceneOpenGL::overlayWindow() const { return m_backend->overlayWindow(); } @@ -823,11 +823,15 @@ } bool SceneOpenGL::viewportLimitsMatched(const QSize &size) const { + if (kwinApp()->operationMode() != Application::OperationModeX11) { + // TODO: On Wayland we can't suspend. Find a solution that works here as well! + return true; + } GLint limit[2]; glGetIntegerv(GL_MAX_VIEWPORT_DIMS, limit); if (limit[0] < size.width() || limit[1] < size.height()) { - QMetaObject::invokeMethod(Compositor::self(), "suspend", - Qt::QueuedConnection, Q_ARG(Compositor::SuspendReason, Compositor::AllReasonSuspend)); + QMetaObject::invokeMethod(static_cast(Compositor::self()), "suspend", + Qt::QueuedConnection, Q_ARG(X11Compositor::SuspendReason, X11Compositor::AllReasonSuspend)); return false; } return true; diff --git a/plugins/scenes/qpainter/scene_qpainter.h b/plugins/scenes/qpainter/scene_qpainter.h --- a/plugins/scenes/qpainter/scene_qpainter.h +++ b/plugins/scenes/qpainter/scene_qpainter.h @@ -35,7 +35,7 @@ public: ~SceneQPainter() override; bool usesOverlayWindow() const override; - OverlayWindow* overlayWindow() override; + OverlayWindow* overlayWindow() const override; qint64 paint(QRegion damage, ToplevelList windows) override; void paintGenericScreen(int mask, ScreenPaintData data) override; CompositingType compositingType() const override; @@ -180,7 +180,7 @@ } inline -OverlayWindow* SceneQPainter::overlayWindow() +OverlayWindow* SceneQPainter::overlayWindow() const { return m_backend->overlayWindow(); } diff --git a/plugins/scenes/xrender/scene_xrender.h b/plugins/scenes/xrender/scene_xrender.h --- a/plugins/scenes/xrender/scene_xrender.h +++ b/plugins/scenes/xrender/scene_xrender.h @@ -159,7 +159,7 @@ Shadow *createShadow(Toplevel *toplevel) override; void screenGeometryChanged(const QSize &size) override; xcb_render_picture_t xrenderBufferPicture() const override; - OverlayWindow *overlayWindow() override { + OverlayWindow *overlayWindow() const override { return m_backend->overlayWindow(); } bool usesOverlayWindow() const override { diff --git a/scene.h b/scene.h --- a/scene.h +++ b/scene.h @@ -147,7 +147,7 @@ virtual void idle(); virtual bool blocksForRetrace() const; virtual bool syncsToVBlank() const; - virtual OverlayWindow* overlayWindow() = 0; + virtual OverlayWindow* overlayWindow() const = 0; virtual bool makeOpenGLContextCurrent(); virtual void doneOpenGLContextCurrent(); diff --git a/workspace.cpp b/workspace.cpp --- a/workspace.cpp +++ b/workspace.cpp @@ -176,7 +176,8 @@ if (Compositor::self()) { m_compositor = Compositor::self(); } else { - m_compositor = Compositor::create(this); + Q_ASSERT(kwinApp()->operationMode() == Application::OperationMode::OperationModeX11); + m_compositor = X11Compositor::create(this); } connect(this, &Workspace::currentDesktopChanged, m_compositor, &Compositor::addRepaintFull); connect(m_compositor, &QObject::destroyed, this, [this] { m_compositor = nullptr; });