From 0489d4a2f6f8d9253af3be1a29b3f2d11fd54428 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Thu, 12 May 2022 11:20:52 +0300 Subject: [PATCH] Merge Workspace::stackingOrder() and Workspace::xStackingOrder() The Workspace has two stacks - one with managed windows and deleted windows, the other includes windows from the first stack + override redirect windows. This change merges both stacks. It has several benefits - we will be able to move window elevation stuff to Workspace and streamline the scene stuff, for example it will be possible to have a root item. Another advantage is that unmanaged windows will have Window::stackingOrder() property set, which can be useful in the future in qml effects or (qtquick scene if we push harder in that front). Another advantage is that kwin will make less X11 calls when restacking managed windows. --- src/composite.cpp | 3 +-- src/effects.cpp | 2 +- src/events.cpp | 12 +++++------- src/layers.cpp | 47 +++++++++++++++++------------------------------ src/scene.cpp | 2 +- src/unmanaged.cpp | 5 +++++ src/unmanaged.h | 5 +---- src/window.cpp | 7 ++++++- src/window.h | 1 + src/workspace.cpp | 24 +++--------------------- src/workspace.h | 6 ------ 11 files changed, 41 insertions(+), 73 deletions(-) diff --git a/src/composite.cpp b/src/composite.cpp index 6ba9e6acb7..4667fc0912 100644 --- a/src/composite.cpp +++ b/src/composite.cpp @@ -364,7 +364,6 @@ void Compositor::startupWithWorkspace() this, &Compositor::cleanupX11, Qt::UniqueConnection); initializeX11(); - Workspace::self()->markXStackingOrderAsDirty(); Q_ASSERT(m_scene); m_scene->initialize(); @@ -891,7 +890,7 @@ void X11Compositor::composite(RenderLoop *renderLoop) return; } - QList windows = Workspace::self()->xStackingOrder(); + QList windows = workspace()->stackingOrder(); QList dirtyItems; // Reset the damage state of each window and fetch the damage region diff --git a/src/effects.cpp b/src/effects.cpp index 8d94396d51..f4a1906b01 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -1110,7 +1110,7 @@ EffectWindow *EffectsHandlerImpl::findWindow(const QUuid &id) const EffectWindowList EffectsHandlerImpl::stackingOrder() const { - QList list = Workspace::self()->xStackingOrder(); + QList list = workspace()->stackingOrder(); EffectWindowList ret; for (Window *t : list) { if (EffectWindow *w = t->effectWindow()) { diff --git a/src/events.cpp b/src/events.cpp index 828bba9f5e..7d92776b44 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -154,14 +154,12 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e) return false; // let Qt process it, it'll be intercepted again in eventFilter() } - // events that should be handled before windows can get them - switch (eventType) { - case XCB_CONFIGURE_NOTIFY: - if (reinterpret_cast(e)->event == kwinApp()->x11RootWindow()) { - markXStackingOrderAsDirty(); + if (eventType == XCB_CONFIGURE_NOTIFY) { + const auto configureNotifyEvent = reinterpret_cast(e); + if (configureNotifyEvent->override_redirect && configureNotifyEvent->event == kwinApp()->x11RootWindow()) { + updateXStackingOrder(); } - break; - }; + } const xcb_window_t eventWindow = findEventWindow(e); if (eventWindow != XCB_WINDOW_NONE) { diff --git a/src/layers.cpp b/src/layers.cpp index 1be2eb3d4c..6c7f510c92 100644 --- a/src/layers.cpp +++ b/src/layers.cpp @@ -108,7 +108,6 @@ void Workspace::updateStackingOrder(bool propagate_new_windows) stacking_order = new_stacking_order; if (changed || propagate_new_windows) { propagateWindows(propagate_new_windows); - markXStackingOrderAsDirty(); for (int i = 0; i < stacking_order.size(); ++i) { stacking_order[i]->setStackingOrder(i); @@ -628,15 +627,6 @@ QList Workspace::ensureStackingOrder(const QList &list) cons return ensureStackingOrderInList(stacking_order, list); } -// Returns all windows in their stacking order on the root window. -QList Workspace::xStackingOrder() const -{ - if (m_xStackingDirty) { - const_cast(this)->updateXStackingOrder(); - } - return x_stacking; -} - QList Workspace::unconstrainedStackingOrder() const { return unconstrained_stacking_order; @@ -644,30 +634,27 @@ QList Workspace::unconstrainedStackingOrder() const void Workspace::updateXStackingOrder() { - // use our own stacking order, not the X one, as they may differ - x_stacking = stacking_order; + // we use our stacking order for managed windows, but X's for override-redirect windows + Xcb::Tree tree(kwinApp()->x11RootWindow()); + xcb_window_t *windows = tree.children(); - if (m_xStackingQueryTree && !m_xStackingQueryTree->isNull()) { - std::unique_ptr tree{std::move(m_xStackingQueryTree)}; - xcb_window_t *windows = tree->children(); - const auto count = tree->data()->children_len; - int foundUnmanagedCount = m_unmanaged.count(); - for (unsigned int i = 0; i < count; ++i) { - for (auto it = m_unmanaged.constBegin(); it != m_unmanaged.constEnd(); ++it) { - Unmanaged *u = *it; - if (u->window() == windows[i]) { - x_stacking.append(u); - foundUnmanagedCount--; - break; - } - } - if (foundUnmanagedCount == 0) { - break; - } + const auto count = tree.data()->children_len; + int remainingCount = m_unmanaged.count(); + for (unsigned int i = 0; i < count; ++i) { + auto window = findUnmanaged(windows[i]); + if (window) { + unconstrained_stacking_order.removeAll(window); + unconstrained_stacking_order.append(window); + remainingCount--; + } + if (remainingCount == 0) { + break; } } - m_xStackingDirty = false; + if (!m_unmanaged.isEmpty()) { + updateStackingOrder(); + } } //******************************* diff --git a/src/scene.cpp b/src/scene.cpp index 4da34f9e75..b8543ee3b8 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -546,7 +546,7 @@ void Scene::paintSimpleScreen(int, const QRegion ®ion) void Scene::createStackingOrder() { // Create a list of all windows in the stacking order - QList windows = Workspace::self()->xStackingOrder(); + QList windows = workspace()->stackingOrder(); // Move elevated windows to the top of the stacking order const QList elevatedList = static_cast(effects)->elevatedWindows(); diff --git a/src/unmanaged.cpp b/src/unmanaged.cpp index 8d4a4e3a56..e5b67ade31 100644 --- a/src/unmanaged.cpp +++ b/src/unmanaged.cpp @@ -214,6 +214,11 @@ bool Unmanaged::isOutline() const return m_outline; } +bool Unmanaged::isUnmanaged() const +{ + return true; +} + QWindow *Unmanaged::findInternalWindow() const { const QWindowList windows = kwinApp()->topLevelWindows(); diff --git a/src/unmanaged.h b/src/unmanaged.h index ae39e526ae..08d77a0559 100644 --- a/src/unmanaged.h +++ b/src/unmanaged.h @@ -30,12 +30,9 @@ public: QStringList activities() const override; QVector desktops() const override; QPoint clientPos() const override; - Layer layer() const override - { - return UnmanagedLayer; - } NET::WindowType windowType(bool direct = false, int supported_types = 0) const override; bool isOutline() const override; + bool isUnmanaged() const override; QString captionNormal() const override { return {}; } QString captionSuffix() const override { return {}; } diff --git a/src/window.cpp b/src/window.cpp index 409686364d..24e4f2d32b 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -533,6 +533,11 @@ bool Window::isClient() const return false; } +bool Window::isUnmanaged() const +{ + return false; +} + bool Window::isDeleted() const { return false; @@ -902,7 +907,7 @@ Layer Window::belongsToLayer() const // and the docks move into the NotificationLayer (which is between Above- and // ActiveLayer, so that active fullscreen windows will still cover everything) // Since the desktop is also activated, nothing should be in the ActiveLayer, though - if (isInternal()) { + if (isUnmanaged() || isInternal()) { return UnmanagedLayer; } if (isLockScreen()) { diff --git a/src/window.h b/src/window.h index 6dce937f48..98098c59d8 100644 --- a/src/window.h +++ b/src/window.h @@ -640,6 +640,7 @@ public: QRect visibleGeometry() const; virtual bool isClient() const; virtual bool isDeleted() const; + virtual bool isUnmanaged() const; /** * Maps the specified @a point from the global screen coordinates to the frame coordinates. diff --git a/src/workspace.cpp b/src/workspace.cpp index e098014c3d..7b6ff8683b 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -467,7 +467,6 @@ void Workspace::cleanupX11() m_nullFocus.reset(); m_syncAlarmFilter.reset(); m_wasUserInteractionFilter.reset(); - m_xStackingQueryTree.reset(); } Workspace::~Workspace() @@ -698,7 +697,6 @@ void Workspace::addX11Window(X11Window *window) m_x11Clients.append(window); m_allClients.append(window); addToStack(window); - markXStackingOrderAsDirty(); updateClientArea(); // This cannot be in manage(), because the window got added only now window->updateLayer(); if (window->isDesktop()) { @@ -720,7 +718,7 @@ void Workspace::addX11Window(X11Window *window) void Workspace::addUnmanaged(Unmanaged *window) { m_unmanaged.append(window); - markXStackingOrderAsDirty(); + addToStack(window); } /** @@ -749,8 +747,8 @@ void Workspace::removeUnmanaged(Unmanaged *window) { Q_ASSERT(m_unmanaged.contains(window)); m_unmanaged.removeAll(window); + removeFromStack(window); Q_EMIT unmanagedRemoved(window); - markXStackingOrderAsDirty(); } void Workspace::addDeleted(Deleted *c, Window *orig) @@ -758,7 +756,6 @@ void Workspace::addDeleted(Deleted *c, Window *orig) Q_ASSERT(!deleted.contains(c)); deleted.append(c); replaceInStack(orig, c); - markXStackingOrderAsDirty(); } void Workspace::removeDeleted(Deleted *c) @@ -767,7 +764,6 @@ void Workspace::removeDeleted(Deleted *c) Q_EMIT deletedRemoved(c); deleted.removeAll(c); removeFromStack(c); - markXStackingOrderAsDirty(); if (!c->wasClient()) { return; } @@ -800,7 +796,6 @@ void Workspace::addWaylandWindow(Window *window) m_allClients.append(window); addToStack(window); - markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); if (window->wantsInput() && !window->isMinimized()) { @@ -809,7 +804,6 @@ void Workspace::addWaylandWindow(Window *window) updateTabbox(); connect(window, &Window::windowShown, this, [this, window] { window->updateLayer(); - markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); if (window->wantsInput()) { @@ -818,7 +812,6 @@ void Workspace::addWaylandWindow(Window *window) }); connect(window, &Window::windowHidden, this, [this] { // TODO: update tabbox if it's displayed - markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); }); @@ -854,7 +847,6 @@ void Workspace::removeAbstractClient(Window *window) } Q_EMIT windowRemoved(window); - markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); @@ -1235,7 +1227,7 @@ void Workspace::slotOutputDisabled(Output *output) disconnect(output, &Output::geometryChanged, this, &Workspace::desktopResized); desktopResized(); - const auto stack = xStackingOrder(); + const auto stack = stackingOrder(); for (Window *window : stack) { if (window->output() == output) { window->setOutput(kwinApp()->platform()->outputAt(window->frameGeometry().center())); @@ -1884,14 +1876,6 @@ Window *Workspace::findInternal(QWindow *w) const return nullptr; } -void Workspace::markXStackingOrderAsDirty() -{ - m_xStackingDirty = true; - if (kwinApp()->x11Connection() && !kwinApp()->isClosingX11Connection()) { - m_xStackingQueryTree.reset(new Xcb::Tree(kwinApp()->x11RootWindow())); - } -} - void Workspace::setWasUserInteraction() { if (was_user_interaction) { @@ -1928,7 +1912,6 @@ void Workspace::addInternalWindow(InternalWindow *window) Placement::self()->place(window, area); } - markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); @@ -1939,7 +1922,6 @@ void Workspace::removeInternalWindow(InternalWindow *window) { m_internalWindows.removeOne(window); - markXStackingOrderAsDirty(); updateStackingOrder(true); updateClientArea(); diff --git a/src/workspace.h b/src/workspace.h index 4df5ebad4d..8eaf2a1512 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -280,7 +280,6 @@ public: * at the last position */ const QList &stackingOrder() const; - QList xStackingOrder() const; QList unconstrainedStackingOrder() const; QList ensureStackingOrder(const QList &windows) const; QList ensureStackingOrder(const QList &windows) const; @@ -388,8 +387,6 @@ public: return m_moveResizeWindow; } - void markXStackingOrderAsDirty(); - void quickTileWindow(QuickTileMode mode); enum Direction { @@ -630,9 +627,6 @@ private: QList stacking_order; // Topmost last QVector manual_overlays; // Topmost last bool force_restacking; - QList x_stacking; // From XQueryTree() - std::unique_ptr m_xStackingQueryTree; - bool m_xStackingDirty = false; QList should_get_focus; // Last is most recent QList attention_chain;