From b4413f4b8b1805e636c2ae19acbc1beaf2b314c5 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 28 Feb 2023 14:57:25 +0200 Subject: [PATCH] scene: Rework window elevation The order in which windows are painted is computed dynamically every frame. On the other hand, with the introduction of items, it's desired to avoid doing that so repaints can be scheduled as needed. The unification also opens the possibilities for more rendering related refactors to make the code nicer and more reusable. --- src/effects.cpp | 9 +++++---- src/effects.h | 11 ----------- src/scene/windowitem.cpp | 24 +++++++++++++++++++++++- src/scene/windowitem.h | 4 ++++ src/scene/workspacescene.cpp | 16 ---------------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/effects.cpp b/src/effects.cpp index c4ce52e312..c773245ba8 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -178,7 +178,6 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, WorkspaceScene *s }); connect(ws, &Workspace::deletedRemoved, this, [this](KWin::Window *d) { Q_EMIT windowDeleted(d->effectWindow()); - elevated_windows.removeAll(d->effectWindow()); }); connect(ws->sessionManager(), &SessionManager::stateChanged, this, &KWin::EffectsHandler::sessionStateChanged); connect(vds, &VirtualDesktopManager::countChanged, this, &EffectsHandler::numberDesktopsChanged); @@ -1097,11 +1096,13 @@ EffectWindowList EffectsHandlerImpl::stackingOrder() const void EffectsHandlerImpl::setElevatedWindow(KWin::EffectWindow *w, bool set) { - elevated_windows.removeAll(w); + WindowItem *item = static_cast(w)->windowItem(); + if (set) { - elevated_windows.append(w); + item->elevate(); + } else { + item->deelevate(); } - addRepaint(w->expandedGeometry()); } void EffectsHandlerImpl::setTabBoxWindow(EffectWindow *w) diff --git a/src/effects.h b/src/effects.h index e78601e3c7..e1b6c61169 100644 --- a/src/effects.h +++ b/src/effects.h @@ -183,8 +183,6 @@ public: QStringList loadedEffects() const; QStringList listOfEffects() const; void unloadAllEffects(); - - QList elevatedWindows() const; QStringList activeEffects() const; /** @@ -313,7 +311,6 @@ protected: Effect *keyboard_grab_effect; Effect *fullscreen_effect; - QList elevated_windows; QMultiMap effect_order; QHash registered_atoms; @@ -621,14 +618,6 @@ private: QRect m_geometry; }; -inline QList EffectsHandlerImpl::elevatedWindows() const -{ - if (isScreenLocked()) { - return QList(); - } - return elevated_windows; -} - inline xcb_window_t EffectsHandlerImpl::x11RootWindow() const { return kwinApp()->x11RootWindow(); diff --git a/src/scene/windowitem.cpp b/src/scene/windowitem.cpp index 3659d6543d..2b8cb9ee4e 100644 --- a/src/scene/windowitem.cpp +++ b/src/scene/windowitem.cpp @@ -124,6 +124,24 @@ void WindowItem::unrefVisible(int reason) updateVisibility(); } +void WindowItem::elevate() +{ + // Not ideal, but it's also highly unlikely that there are more than 1000 windows. The + // elevation constantly increases so it's possible to force specific stacking order. It + // can potentially overflow, but it's unlikely to happen because windows are elevated + // rarely. + static int elevation = 1000; + + m_elevation = elevation++; + updateStackingOrder(); +} + +void WindowItem::deelevate() +{ + m_elevation.reset(); + updateStackingOrder(); +} + void WindowItem::handleWindowClosed(Window *original, Window *deleted) { m_window = deleted; @@ -262,7 +280,11 @@ void WindowItem::updateOpacity() void WindowItem::updateStackingOrder() { - setZ(m_window->stackingOrder()); + if (m_elevation.has_value()) { + setZ(m_elevation.value()); + } else { + setZ(m_window->stackingOrder()); + } } void WindowItem::markDamaged() diff --git a/src/scene/windowitem.h b/src/scene/windowitem.h index 1971f9e29d..2ebde224e0 100644 --- a/src/scene/windowitem.h +++ b/src/scene/windowitem.h @@ -51,6 +51,9 @@ public: void refVisible(int reason); void unrefVisible(int reason); + void elevate(); + void deelevate(); + protected: explicit WindowItem(Window *window, Scene *scene, Item *parent = nullptr); void updateSurfaceItem(SurfaceItem *surfaceItem); @@ -75,6 +78,7 @@ private: std::unique_ptr m_surfaceItem; std::unique_ptr m_decorationItem; std::unique_ptr m_shadowItem; + std::optional m_elevation; int m_forceVisibleByHiddenCount = 0; int m_forceVisibleByDeleteCount = 0; int m_forceVisibleByDesktopCount = 0; diff --git a/src/scene/workspacescene.cpp b/src/scene/workspacescene.cpp index f44174145d..bdc9b23eff 100644 --- a/src/scene/workspacescene.cpp +++ b/src/scene/workspacescene.cpp @@ -427,23 +427,7 @@ void WorkspaceScene::paintSimpleScreen(const RenderTarget &renderTarget, const R void WorkspaceScene::createStackingOrder() { - // Create a list of all windows in the stacking order QList items = m_containerItem->sortedChildItems(); - - // Move elevated windows to the top of the stacking order - const QList elevatedList = static_cast(effects)->elevatedWindows(); - for (EffectWindow *c : elevatedList) { - WindowItem *item = static_cast(c)->windowItem(); - items.removeAll(item); - items.append(item); - } - - // Skip windows that are not yet ready for being painted and if screen is locked skip windows - // that are neither lockscreen nor inputmethod windows. - // - // TODO? This cannot be used so carelessly - needs protections against broken clients, the - // window should not get focus before it's displayed, handle unredirected windows properly and - // so on. for (Item *item : std::as_const(items)) { WindowItem *windowItem = static_cast(item); if (windowItem->isVisible()) {