diff --git a/autotests/test_window_paint_data.cpp b/autotests/test_window_paint_data.cpp --- a/autotests/test_window_paint_data.cpp +++ b/autotests/test_window_paint_data.cpp @@ -248,6 +248,9 @@ bool isX11Client() const override { return false; } + bool isOutline() const override { + return false; + } private: qreal m_opacity = 1.0; diff --git a/deleted.h b/deleted.h --- a/deleted.h +++ b/deleted.h @@ -177,6 +177,13 @@ QVector x11DesktopIds() const; + /** + * Whether this Deleted represents the outline. + **/ + bool isOutline() const override { + return m_wasOutline; + } + protected: virtual void debug(QDebug& stream) const; @@ -229,6 +236,7 @@ ToplevelList m_transientFor; DeletedList m_transients; bool m_wasPopupWindow; + bool m_wasOutline; }; inline void Deleted::refWindow() diff --git a/deleted.cpp b/deleted.cpp --- a/deleted.cpp +++ b/deleted.cpp @@ -53,6 +53,7 @@ , m_wasWaylandClient(false) , m_wasGroupTransient(false) , m_wasPopupWindow(false) + , m_wasOutline(false) { } @@ -149,6 +150,7 @@ m_wasWaylandClient = qobject_cast(c) != nullptr; m_wasX11Client = !m_wasWaylandClient; m_wasPopupWindow = c->isPopupWindow(); + m_wasOutline = c->isOutline(); } void Deleted::unrefWindow() diff --git a/effects.h b/effects.h --- a/effects.h +++ b/effects.h @@ -442,6 +442,7 @@ bool keepBelow() const override; bool isModal() const override; bool isPopupWindow() const override; + bool isOutline() const override; KWayland::Server::SurfaceInterface *surface() const override; bool isFullScreen() const override; diff --git a/effects.cpp b/effects.cpp --- a/effects.cpp +++ b/effects.cpp @@ -1832,6 +1832,7 @@ TOPLEVEL_HELPER(bool, skipsCloseAnimation, skipsCloseAnimation) TOPLEVEL_HELPER(KWayland::Server::SurfaceInterface *, surface, surface) TOPLEVEL_HELPER(bool, isPopupWindow, isPopupWindow) +TOPLEVEL_HELPER(bool, isOutline, isOutline) #undef TOPLEVEL_HELPER diff --git a/effects/fade/package/contents/code/main.js b/effects/fade/package/contents/code/main.js --- a/effects/fade/package/contents/code/main.js +++ b/effects/fade/package/contents/code/main.js @@ -43,6 +43,9 @@ if (!w.visible) { return false; } + if (w.outline) { + return false; + } if (w.deleted && effect.isGrabbed(w, Effect.WindowClosedGrabRole)) { return false; } else if (!w.deleted && effect.isGrabbed(w, Effect.WindowAddedGrabRole)) { diff --git a/effects/fadingpopups/package/contents/code/main.js b/effects/fadingpopups/package/contents/code/main.js --- a/effects/fadingpopups/package/contents/code/main.js +++ b/effects/fadingpopups/package/contents/code/main.js @@ -42,6 +42,11 @@ return true; } + // Maybe the outline deserves its own effect. + if (window.outline) { + return true; + } + // Override-redirect windows are usually used for user interface // concepts that are expected to be animated by this effect, e.g. // popups that contain window thumbnails on X11, etc. diff --git a/effects/glide/glide.cpp b/effects/glide/glide.cpp --- a/effects/glide/glide.cpp +++ b/effects/glide/glide.cpp @@ -319,6 +319,11 @@ return false; } + // Dont't animate the outline because it looks very sick. + if (w->isOutline()) { + return false; + } + // Override-redirect windows are usually used for user interface // concepts that are not expected to be animated by this effect. if (w->isX11Client() && !w->isManaged()) { diff --git a/effects/scale/package/contents/code/main.js b/effects/scale/package/contents/code/main.js --- a/effects/scale/package/contents/code/main.js +++ b/effects/scale/package/contents/code/main.js @@ -66,6 +66,11 @@ return false; } + // Dont't animate the outline because it looks very sick. + if (window.outline) { + return false; + } + // Override-redirect windows are usually used for user interface // concepts that are not expected to be animated by this effect. if (window.x11Client && !window.managed) { diff --git a/internal_client.h b/internal_client.h --- a/internal_client.h +++ b/internal_client.h @@ -55,6 +55,7 @@ bool isInternal() const override; bool isLockScreen() const override; bool isInputMethod() const override; + bool isOutline() const override; quint32 windowId() const override; using AbstractClient::resizeWithChecks; void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet) override; diff --git a/internal_client.cpp b/internal_client.cpp --- a/internal_client.cpp +++ b/internal_client.cpp @@ -211,6 +211,14 @@ return false; } +bool InternalClient::isOutline() const +{ + if (m_internalWindow) { + return m_internalWindow->property("__kwin_outline").toBool(); + } + return false; +} + quint32 InternalClient::windowId() const { return m_windowId; diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -2066,6 +2066,15 @@ **/ Q_PROPERTY(QWindow *internalWindow READ internalWindow CONSTANT) + /** + * Whether this EffectWindow represents the outline. + * + * When compositing is turned on, the outline is an actual window. + * + * @since 5.16 + **/ + Q_PROPERTY(bool outline READ isOutline CONSTANT) + public: /** Flags explaining why painting should be disabled */ enum { @@ -2354,6 +2363,11 @@ **/ virtual QWindow *internalWindow() const = 0; + /** + * @since 5.16 + **/ + virtual bool isOutline() const = 0; + /** * Can be used to by effects to store arbitrary data in the EffectWindow. * diff --git a/outline.cpp b/outline.cpp --- a/outline.cpp +++ b/outline.cpp @@ -180,6 +180,9 @@ } else { m_mainItem.reset(m_qmlComponent->create(m_qmlContext.data())); } + if (auto w = qobject_cast(m_mainItem.data())) { + w->setProperty("__kwin_outline", true); + } } } diff --git a/toplevel.h b/toplevel.h --- a/toplevel.h +++ b/toplevel.h @@ -216,6 +216,13 @@ **/ Q_PROPERTY(bool popupWindow READ isPopupWindow) + /** + * Whether this Toplevel represents the outline. + * + * @note It's always @c false if compositing is turned off. + **/ + Q_PROPERTY(bool outline READ isOutline) + public: explicit Toplevel(); virtual xcb_window_t frameId() const; @@ -283,6 +290,7 @@ virtual bool isLockScreen() const; virtual bool isInputMethod() const; + virtual bool isOutline() const; /** * Returns the virtual desktop within the workspace() the client window @@ -764,6 +772,11 @@ return false; } +inline bool Toplevel::isOutline() const +{ + return false; +} + inline QRegion Toplevel::damage() const { return damage_region; diff --git a/unmanaged.h b/unmanaged.h --- a/unmanaged.h +++ b/unmanaged.h @@ -47,6 +47,7 @@ return UnmanagedLayer; } NET::WindowType windowType(bool direct = false, int supported_types = 0) const; + bool isOutline() const override; public Q_SLOTS: void release(ReleaseReason releaseReason = ReleaseReason::Release); @@ -57,6 +58,8 @@ virtual ~Unmanaged(); // use release() // handlers for X11 events void configureNotifyEvent(xcb_configure_notify_event_t *e); + QWindow *findInternalWindow() const; + bool m_outline = false; }; } // namespace diff --git a/unmanaged.cpp b/unmanaged.cpp --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -28,6 +28,7 @@ #include #include +#include #include @@ -81,6 +82,9 @@ getWmOpaqueRegion(); getSkipCloseAnimation(); setupCompositing(); + if (QWindow *internalWindow = findInternalWindow()) { + m_outline = internalWindow->property("__kwin_outline").toBool(); + } if (effects) static_cast(effects)->checkInputWindowStacking(); return true; @@ -159,11 +163,27 @@ return info->windowType(NET::WindowTypes(supportedTypes)); } +bool Unmanaged::isOutline() const +{ + return m_outline; +} + void Unmanaged::addDamage(const QRegion &damage) { repaints_region += damage; Toplevel::addDamage(damage); } +QWindow *Unmanaged::findInternalWindow() const +{ + const QWindowList windows = kwinApp()->topLevelWindows(); + for (QWindow *w : windows) { + if (w->winId() == window()) { + return w; + } + } + return nullptr; +} + } // namespace