File indexing completed on 2024-11-10 04:57:49

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 1999, 2000 Matthias Ettrich <ettrich@kde.org>
0006     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 // SELI zmenit doc
0012 
0013 /*
0014 
0015  This file contains things relevant to stacking order and layers.
0016 
0017  Design:
0018 
0019  Normal unconstrained stacking order, as requested by the user (by clicking
0020  on windows to raise them, etc.), is in Workspace::unconstrained_stacking_order.
0021  That list shouldn't be used at all, except for building
0022  Workspace::stacking_order. The building is done
0023  in Workspace::constrainedStackingOrder(). Only Workspace::stackingOrder() should
0024  be used to get the stacking order, because it also checks the stacking order
0025  is up to date.
0026  All clients are also stored in Workspace::clients (except for isDesktop() clients,
0027  as those are very special, and are stored in Workspace::desktops), in the order
0028  the clients were created.
0029 
0030  Every window has one layer assigned in which it is. There are 7 layers,
0031  from bottom : DesktopLayer, BelowLayer, NormalLayer, DockLayer, AboveLayer, NotificationLayer,
0032  ActiveLayer, CriticalNotificationLayer, and OnScreenDisplayLayer (see also NETWM sect.7.10.).
0033  The layer a window is in depends on the window type, and on other things like whether the window
0034  is active. We extend the layers provided in NETWM by the NotificationLayer, OnScreenDisplayLayer,
0035  and CriticalNotificationLayer.
0036  The NoficationLayer contains notification windows which are kept above all windows except the active
0037  fullscreen window. The CriticalNotificationLayer contains notification windows which are important
0038  enough to keep them even above fullscreen windows. The OnScreenDisplayLayer is used for eg. volume
0039  and brightness change feedback and is kept above all windows since it provides immediate response
0040  to a user action.
0041 
0042  NET::Splash clients belong to the Normal layer. NET::TopMenu clients
0043  belong to Dock layer. Clients that are both NET::Dock and NET::KeepBelow
0044  are in the Normal layer in order to keep the 'allow window to cover
0045  the panel' Kicker setting to work as intended (this may look like a slight
0046  spec violation, but a) I have no better idea, b) the spec allows adjusting
0047  the stacking order if the WM thinks it's a good idea . We put all
0048  NET::KeepAbove above all Docks too, even though the spec suggests putting
0049  them in the same layer.
0050 
0051  Most transients are in the same layer as their mainwindow,
0052  see Workspace::constrainedStackingOrder(), they may also be in higher layers, but
0053  they should never be below their mainwindow.
0054 
0055  Currently the things that affect client in which layer a client
0056  belongs: KeepAbove/Keep Below flags, window type, fullscreen
0057  state and whether the client is active, mainclient (transiency).
0058 
0059  Make sure updateStackingOrder() is called in order to make
0060  Workspace::stackingOrder() up to date and propagated to the world.
0061  Using Workspace::blockStackingUpdates() (or the StackingUpdatesBlocker
0062  helper class) it's possible to temporarily disable updates
0063  and the stacking order will be updated once after it's allowed again.
0064 
0065 */
0066 
0067 #include "compositor.h"
0068 #include "effect/effecthandler.h"
0069 #include "focuschain.h"
0070 #include "group.h"
0071 #include "internalwindow.h"
0072 #include "netinfo.h"
0073 #include "rules.h"
0074 #include "screenedge.h"
0075 #include "tabbox/tabbox.h"
0076 #include "utils/common.h"
0077 #include "virtualdesktops.h"
0078 #include "wayland_server.h"
0079 #include "workspace.h"
0080 #include "x11window.h"
0081 
0082 #include <array>
0083 
0084 #include <QDebug>
0085 
0086 namespace KWin
0087 {
0088 
0089 //*******************************
0090 // Workspace
0091 //*******************************
0092 
0093 void Workspace::updateStackingOrder(bool propagate_new_windows)
0094 {
0095     if (m_blockStackingUpdates > 0) {
0096         if (propagate_new_windows) {
0097             m_blockedPropagatingNewWindows = true;
0098         }
0099         return;
0100     }
0101     QList<Window *> new_stacking_order = constrainedStackingOrder();
0102     bool changed = (force_restacking || new_stacking_order != stacking_order);
0103     force_restacking = false;
0104     stacking_order = new_stacking_order;
0105     if (changed || propagate_new_windows) {
0106         propagateWindows(propagate_new_windows);
0107 
0108         for (int i = 0; i < stacking_order.size(); ++i) {
0109             stacking_order[i]->setStackingOrder(i);
0110         }
0111 
0112         Q_EMIT stackingOrderChanged();
0113 
0114         if (m_activeWindow) {
0115             m_activeWindow->updateMouseGrab();
0116         }
0117     }
0118 }
0119 
0120 /**
0121  * Some fullscreen effects have to raise the screenedge on top of an input window, thus all windows
0122  * this function puts them back where they belong for regular use and is some cheap variant of
0123  * the regular propagateWindows function in that it completely ignores managed windows and everything
0124  * else and also does not update the NETWM property.
0125  * Called from Effects::destroyInputWindow so far.
0126  */
0127 void Workspace::stackScreenEdgesUnderOverrideRedirect()
0128 {
0129     if (!rootInfo()) {
0130         return;
0131     }
0132     Xcb::restackWindows(QList<xcb_window_t>() << rootInfo()->supportWindow() << workspace()->screenEdges()->windows());
0133 }
0134 
0135 /**
0136  * Propagates the managed windows to the world.
0137  * Called ONLY from updateStackingOrder().
0138  */
0139 void Workspace::propagateWindows(bool propagate_new_windows)
0140 {
0141     if (!rootInfo()) {
0142         return;
0143     }
0144     // restack the windows according to the stacking order
0145     // supportWindow > electric borders > windows > hidden windows
0146     QList<xcb_window_t> newWindowStack;
0147 
0148     // Stack all windows under the support window. The support window is
0149     // not used for anything (besides the NETWM property), and it's not shown,
0150     // but it was lowered after kwin startup. Stacking all windows below
0151     // it ensures that no window will be ever shown above override-redirect
0152     // windows (e.g. popups).
0153     newWindowStack << rootInfo()->supportWindow();
0154 
0155     newWindowStack << workspace()->screenEdges()->windows();
0156 
0157     newWindowStack << manual_overlays;
0158 
0159     newWindowStack.reserve(newWindowStack.size() + 2 * stacking_order.size()); // *2 for inputWindow
0160 
0161     for (int i = stacking_order.size() - 1; i >= 0; --i) {
0162         X11Window *window = qobject_cast<X11Window *>(stacking_order.at(i));
0163         if (!window || window->isUnmanaged() || window->hiddenPreview()) {
0164             continue;
0165         }
0166 
0167         if (window->inputId()) {
0168             // Stack the input window above the frame
0169             newWindowStack << window->inputId();
0170         }
0171 
0172         newWindowStack << window->frameId();
0173     }
0174 
0175     // when having hidden previews, stack hidden windows below everything else
0176     // (as far as pure X stacking order is concerned), in order to avoid having
0177     // these windows that should be unmapped to interfere with other windows
0178     for (int i = stacking_order.size() - 1; i >= 0; --i) {
0179         X11Window *window = qobject_cast<X11Window *>(stacking_order.at(i));
0180         if (!window || window->isUnmanaged() || !window->hiddenPreview()) {
0181             continue;
0182         }
0183         newWindowStack << window->frameId();
0184     }
0185     // TODO isn't it too inefficient to restack always all windows?
0186     // TODO don't restack not visible windows?
0187     Q_ASSERT(newWindowStack.at(0) == rootInfo()->supportWindow());
0188     Xcb::restackWindows(newWindowStack);
0189 
0190     QList<xcb_window_t> cl;
0191     if (propagate_new_windows) {
0192         cl.reserve(manual_overlays.size() + m_windows.size());
0193         for (const auto win : std::as_const(manual_overlays)) {
0194             cl.push_back(win);
0195         }
0196         for (Window *window : std::as_const(m_windows)) {
0197             X11Window *x11Window = qobject_cast<X11Window *>(window);
0198             if (x11Window && !x11Window->isUnmanaged()) {
0199                 cl.push_back(x11Window->window());
0200             }
0201         }
0202         rootInfo()->setClientList(cl.constData(), cl.size());
0203     }
0204 
0205     cl.clear();
0206     for (auto it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) {
0207         X11Window *window = qobject_cast<X11Window *>(*it);
0208         if (window && !window->isUnmanaged()) {
0209             cl.push_back(window->window());
0210         }
0211     }
0212     for (const auto win : std::as_const(manual_overlays)) {
0213         cl.push_back(win);
0214     }
0215     rootInfo()->setClientListStacking(cl.constData(), cl.size());
0216 }
0217 
0218 /**
0219  * Returns topmost visible window. Windows on the dock, the desktop
0220  * or of any other special kind are excluded. Also if the window
0221  * doesn't accept focus it's excluded.
0222  */
0223 // TODO misleading name for this method, too many slightly different ways to use it
0224 Window *Workspace::topWindowOnDesktop(VirtualDesktop *desktop, Output *output, bool unconstrained, bool only_normal) const
0225 {
0226     // TODO    Q_ASSERT( block_stacking_updates == 0 );
0227     QList<Window *> list;
0228     if (!unconstrained) {
0229         list = stacking_order;
0230     } else {
0231         list = unconstrained_stacking_order;
0232     }
0233     for (int i = list.size() - 1; i >= 0; --i) {
0234         auto window = list.at(i);
0235         if (!window->isClient() || window->isDeleted()) {
0236             continue;
0237         }
0238         if (window->isOnDesktop(desktop) && window->isShown() && window->isOnCurrentActivity() && !window->isShade()) {
0239             if (output && window->output() != output) {
0240                 continue;
0241             }
0242             if (!only_normal) {
0243                 return window;
0244             }
0245             if (window->wantsTabFocus() && !window->isSpecialWindow()) {
0246                 return window;
0247             }
0248         }
0249     }
0250     return nullptr;
0251 }
0252 
0253 Window *Workspace::findDesktop(bool topmost, VirtualDesktop *desktop) const
0254 {
0255     // TODO    Q_ASSERT( block_stacking_updates == 0 );
0256     if (topmost) {
0257         for (int i = stacking_order.size() - 1; i >= 0; i--) {
0258             auto window = stacking_order.at(i);
0259             if (window->isDeleted()) {
0260                 continue;
0261             }
0262             if (window->isClient() && window->isOnDesktop(desktop) && window->isDesktop() && window->isShown()) {
0263                 return window;
0264             }
0265         }
0266     } else { // bottom-most
0267         for (Window *window : std::as_const(stacking_order)) {
0268             if (window->isDeleted()) {
0269                 continue;
0270             }
0271             if (window->isClient() && window->isOnDesktop(desktop) && window->isDesktop() && window->isShown()) {
0272                 return window;
0273             }
0274         }
0275     }
0276     return nullptr;
0277 }
0278 
0279 void Workspace::raiseOrLowerWindow(Window *window)
0280 {
0281     if (!window->isOnCurrentDesktop()) {
0282         return;
0283     }
0284 
0285     const Window *topmost =
0286         topWindowOnDesktop(VirtualDesktopManager::self()->currentDesktop(),
0287                            options->isSeparateScreenFocus() ? window->output() : nullptr);
0288 
0289     if (window == topmost) {
0290         lowerWindow(window);
0291     } else {
0292         raiseWindow(window);
0293     }
0294 }
0295 
0296 void Workspace::lowerWindow(Window *window, bool nogroup)
0297 {
0298     if (window->isDeleted()) {
0299         qCWarning(KWIN_CORE) << "Workspace::lowerWindow: closed window" << window << "cannot be restacked";
0300         return;
0301     }
0302 
0303     window->cancelAutoRaise();
0304 
0305     StackingUpdatesBlocker blocker(this);
0306 
0307     unconstrained_stacking_order.removeAll(window);
0308     unconstrained_stacking_order.prepend(window);
0309     if (!nogroup && window->isTransient()) {
0310         // lower also all windows in the group, in their reversed stacking order
0311         QList<X11Window *> wins;
0312         if (auto group = window->group()) {
0313             wins = ensureStackingOrder(group->members());
0314         }
0315         for (int i = wins.size() - 1; i >= 0; --i) {
0316             if (wins[i] != window) {
0317                 lowerWindow(wins[i], true);
0318             }
0319         }
0320     }
0321 }
0322 
0323 void Workspace::lowerWindowWithinApplication(Window *window)
0324 {
0325     if (window->isDeleted()) {
0326         qCWarning(KWIN_CORE) << "Workspace::lowerWindowWithinApplication: closed window" << window << "cannot be restacked";
0327         return;
0328     }
0329 
0330     window->cancelAutoRaise();
0331 
0332     StackingUpdatesBlocker blocker(this);
0333 
0334     unconstrained_stacking_order.removeAll(window);
0335     bool lowered = false;
0336     // first try to put it below the bottom-most window of the application
0337     for (auto it = unconstrained_stacking_order.begin(); it != unconstrained_stacking_order.end(); ++it) {
0338         auto other = *it;
0339         if (!other->isClient() || other->isDeleted()) {
0340             continue;
0341         }
0342         if (Window::belongToSameApplication(other, window)) {
0343             unconstrained_stacking_order.insert(it, window);
0344             lowered = true;
0345             break;
0346         }
0347     }
0348     if (!lowered) {
0349         unconstrained_stacking_order.prepend(window);
0350     }
0351     // ignore mainwindows
0352 }
0353 
0354 void Workspace::raiseWindow(Window *window, bool nogroup)
0355 {
0356     if (window->isDeleted()) {
0357         qCWarning(KWIN_CORE) << "Workspace::raiseWindow: closed window" << window << "cannot be restacked";
0358         return;
0359     }
0360 
0361     window->cancelAutoRaise();
0362 
0363     StackingUpdatesBlocker blocker(this);
0364 
0365     if (!nogroup && window->isTransient()) {
0366         QList<Window *> transients;
0367         Window *transient_parent = window;
0368         while ((transient_parent = transient_parent->transientFor())) {
0369             transients.prepend(transient_parent);
0370         }
0371         for (const auto &transient_parent : std::as_const(transients)) {
0372             raiseWindow(transient_parent, true);
0373         }
0374     }
0375 
0376     unconstrained_stacking_order.removeAll(window);
0377     unconstrained_stacking_order.append(window);
0378 }
0379 
0380 void Workspace::raiseWindowWithinApplication(Window *window)
0381 {
0382     if (window->isDeleted()) {
0383         qCWarning(KWIN_CORE) << "Workspace::raiseWindowWithinApplication: closed window" << window << "cannot be restacked";
0384         return;
0385     }
0386 
0387     window->cancelAutoRaise();
0388 
0389     StackingUpdatesBlocker blocker(this);
0390     // ignore mainwindows
0391 
0392     // first try to put it above the top-most window of the application
0393     for (int i = unconstrained_stacking_order.size() - 1; i > -1; --i) {
0394         auto other = unconstrained_stacking_order.at(i);
0395         if (!other->isClient() || other->isDeleted()) {
0396             continue;
0397         }
0398         if (other == window) { // don't lower it just because it asked to be raised
0399             return;
0400         }
0401         if (Window::belongToSameApplication(other, window)) {
0402             unconstrained_stacking_order.removeAll(window);
0403             unconstrained_stacking_order.insert(unconstrained_stacking_order.indexOf(other) + 1, window); // insert after the found one
0404             break;
0405         }
0406     }
0407 }
0408 
0409 void Workspace::raiseWindowRequest(Window *window, NET::RequestSource src, xcb_timestamp_t timestamp)
0410 {
0411     if (src == NET::FromTool || allowFullClientRaising(window, timestamp)) {
0412         raiseWindow(window);
0413     } else {
0414         raiseWindowWithinApplication(window);
0415         window->demandAttention();
0416     }
0417 }
0418 
0419 void Workspace::lowerWindowRequest(X11Window *window, NET::RequestSource src, xcb_timestamp_t /*timestamp*/)
0420 {
0421     // If the window has support for all this focus stealing prevention stuff,
0422     // do only lowering within the application, as that's the more logical
0423     // variant of lowering when application requests it.
0424     // No demanding of attention here of course.
0425     if (src == NET::FromTool || !window->hasUserTimeSupport()) {
0426         lowerWindow(window);
0427     } else {
0428         lowerWindowWithinApplication(window);
0429     }
0430 }
0431 
0432 void Workspace::lowerWindowRequest(Window *window)
0433 {
0434     lowerWindowWithinApplication(window);
0435 }
0436 
0437 void Workspace::restack(Window *window, Window *under, bool force)
0438 {
0439     if (window->isDeleted()) {
0440         qCWarning(KWIN_CORE) << "Workspace::restack: closed window" << window << "cannot be restacked";
0441         return;
0442     }
0443     Q_ASSERT(unconstrained_stacking_order.contains(under));
0444     if (!force && !Window::belongToSameApplication(under, window)) {
0445         // put in the stacking order below _all_ windows belonging to the active application
0446         for (int i = 0; i < unconstrained_stacking_order.size(); ++i) {
0447             auto other = unconstrained_stacking_order.at(i);
0448             if (other->isClient() && other->layer() == window->layer() && Window::belongToSameApplication(under, other)) {
0449                 under = (window == other) ? nullptr : other;
0450                 break;
0451             }
0452         }
0453     }
0454     if (under) {
0455         unconstrained_stacking_order.removeAll(window);
0456         unconstrained_stacking_order.insert(unconstrained_stacking_order.indexOf(under), window);
0457     }
0458 
0459     Q_ASSERT(unconstrained_stacking_order.contains(window));
0460     m_focusChain->moveAfterWindow(window, under);
0461     updateStackingOrder();
0462 }
0463 
0464 void Workspace::restackWindowUnderActive(Window *window)
0465 {
0466     if (!m_activeWindow || m_activeWindow == window || m_activeWindow->layer() != window->layer()) {
0467         raiseWindow(window);
0468         return;
0469     }
0470     restack(window, m_activeWindow);
0471 }
0472 
0473 void Workspace::restoreSessionStackingOrder(X11Window *window)
0474 {
0475     if (window->sessionStackingOrder() < 0) {
0476         return;
0477     }
0478     StackingUpdatesBlocker blocker(this);
0479     unconstrained_stacking_order.removeAll(window);
0480     for (auto it = unconstrained_stacking_order.begin(); it != unconstrained_stacking_order.end(); ++it) {
0481         X11Window *current = qobject_cast<X11Window *>(*it);
0482         if (!current || current->isDeleted() || current->isUnmanaged()) {
0483             continue;
0484         }
0485         if (current->sessionStackingOrder() > window->sessionStackingOrder()) {
0486             unconstrained_stacking_order.insert(it, window);
0487             return;
0488         }
0489     }
0490     unconstrained_stacking_order.append(window);
0491 }
0492 
0493 static Layer layerForWindow(const X11Window *window)
0494 {
0495     Layer layer = window->layer();
0496 
0497     // Desktop windows cannot be promoted to upper layers.
0498     if (layer == DesktopLayer) {
0499         return layer;
0500     }
0501 
0502     if (const Group *group = window->group()) {
0503         const auto members = group->members();
0504         for (const X11Window *member : members) {
0505             if (member == window) {
0506                 continue;
0507             } else if (member->output() != window->output()) {
0508                 continue;
0509             }
0510             if (member->layer() == ActiveLayer) {
0511                 return ActiveLayer;
0512             }
0513         }
0514     }
0515 
0516     return layer;
0517 }
0518 
0519 static Layer computeLayer(const Window *window)
0520 {
0521     if (auto x11Window = qobject_cast<const X11Window *>(window)) {
0522         return layerForWindow(x11Window);
0523     } else {
0524         return window->layer();
0525     }
0526 }
0527 
0528 /**
0529  * Returns a stacking order based upon \a list that fulfills certain contained.
0530  */
0531 QList<Window *> Workspace::constrainedStackingOrder()
0532 {
0533     // Sort the windows based on their layers while preserving their relative order in the
0534     // unconstrained stacking order.
0535     std::array<QList<Window *>, NumLayers> windows;
0536     for (Window *window : std::as_const(unconstrained_stacking_order)) {
0537         const Layer layer = computeLayer(window);
0538         windows[layer] << window;
0539     }
0540 
0541     QList<Window *> stacking;
0542     stacking.reserve(unconstrained_stacking_order.count());
0543     for (uint layer = FirstLayer; layer < NumLayers; ++layer) {
0544         stacking += windows[layer];
0545     }
0546 
0547     // Apply the stacking order constraints. First, we enqueue the root constraints, i.e.
0548     // the ones that are not affected by other constraints.
0549     QList<Constraint *> constraints;
0550     constraints.reserve(m_constraints.count());
0551     for (Constraint *constraint : std::as_const(m_constraints)) {
0552         if (constraint->parents.isEmpty()) {
0553             constraint->enqueued = true;
0554             constraints.append(constraint);
0555         } else {
0556             constraint->enqueued = false;
0557         }
0558     }
0559 
0560     // Preserve the relative order of transient siblings in the unconstrained stacking order.
0561     auto constraintComparator = [&stacking](Constraint *a, Constraint *b) {
0562         return stacking.indexOf(a->above) > stacking.indexOf(b->above);
0563     };
0564     std::sort(constraints.begin(), constraints.end(), constraintComparator);
0565 
0566     // Once we've enqueued all the root constraints, we traverse the constraints tree in
0567     // the reverse breadth-first search fashion. A constraint is applied only if its condition is
0568     // not met.
0569     while (!constraints.isEmpty()) {
0570         Constraint *constraint = constraints.takeFirst();
0571 
0572         const int belowIndex = stacking.indexOf(constraint->below);
0573         const int aboveIndex = stacking.indexOf(constraint->above);
0574         if (belowIndex == -1 || aboveIndex == -1) {
0575             continue;
0576         } else if (aboveIndex < belowIndex) {
0577             stacking.removeAt(aboveIndex);
0578             stacking.insert(belowIndex, constraint->above);
0579         }
0580 
0581         // Preserve the relative order of transient siblings in the unconstrained stacking order.
0582         QList<Constraint *> children = constraint->children;
0583         std::sort(children.begin(), children.end(), constraintComparator);
0584 
0585         for (Constraint *child : std::as_const(children)) {
0586             if (!child->enqueued) {
0587                 child->enqueued = true;
0588                 constraints.append(child);
0589             }
0590         }
0591     }
0592 
0593     return stacking;
0594 }
0595 
0596 void Workspace::blockStackingUpdates(bool block)
0597 {
0598     if (block) {
0599         if (m_blockStackingUpdates == 0) {
0600             m_blockedPropagatingNewWindows = false;
0601         }
0602         ++m_blockStackingUpdates;
0603     } else // !block
0604         if (--m_blockStackingUpdates == 0) {
0605             updateStackingOrder(m_blockedPropagatingNewWindows);
0606             if (effects) {
0607                 effects->checkInputWindowStacking();
0608             }
0609         }
0610 }
0611 
0612 namespace
0613 {
0614 template<class T>
0615 QList<T *> ensureStackingOrderInList(const QList<Window *> &stackingOrder, const QList<T *> &list)
0616 {
0617     static_assert(std::is_base_of<Window, T>::value,
0618                   "U must be derived from T");
0619     // TODO    Q_ASSERT( block_stacking_updates == 0 );
0620     if (list.count() < 2) {
0621         return list;
0622     }
0623     // TODO is this worth optimizing?
0624     QList<T *> result = list;
0625     for (auto it = stackingOrder.begin(); it != stackingOrder.end(); ++it) {
0626         T *window = qobject_cast<T *>(*it);
0627         if (!window) {
0628             continue;
0629         }
0630         if (result.removeAll(window) != 0) {
0631             result.append(window);
0632         }
0633     }
0634     return result;
0635 }
0636 }
0637 
0638 // Ensure list is in stacking order
0639 QList<X11Window *> Workspace::ensureStackingOrder(const QList<X11Window *> &list) const
0640 {
0641     return ensureStackingOrderInList(stacking_order, list);
0642 }
0643 
0644 QList<Window *> Workspace::ensureStackingOrder(const QList<Window *> &list) const
0645 {
0646     return ensureStackingOrderInList(stacking_order, list);
0647 }
0648 
0649 QList<Window *> Workspace::unconstrainedStackingOrder() const
0650 {
0651     return unconstrained_stacking_order;
0652 }
0653 
0654 void Workspace::updateXStackingOrder()
0655 {
0656     // we use our stacking order for managed windows, but X's for override-redirect windows
0657     Xcb::Tree tree(kwinApp()->x11RootWindow());
0658     xcb_window_t *windows = tree.children();
0659 
0660     const auto count = tree.data()->children_len;
0661     bool changed = false;
0662     for (unsigned int i = 0; i < count; ++i) {
0663         auto window = findUnmanaged(windows[i]);
0664         if (window) {
0665             unconstrained_stacking_order.removeAll(window);
0666             unconstrained_stacking_order.append(window);
0667             changed = true;
0668         }
0669     }
0670 
0671     if (changed) {
0672         updateStackingOrder();
0673     }
0674 }
0675 
0676 //*******************************
0677 // Client
0678 //*******************************
0679 
0680 void X11Window::restackWindow(xcb_window_t above, int detail, NET::RequestSource src, xcb_timestamp_t timestamp, bool send_event)
0681 {
0682     X11Window *other = nullptr;
0683     if (detail == XCB_STACK_MODE_OPPOSITE) {
0684         other = workspace()->findClient(Predicate::WindowMatch, above);
0685         if (!other) {
0686             workspace()->raiseOrLowerWindow(this);
0687             return;
0688         }
0689         auto it = workspace()->stackingOrder().constBegin(),
0690              end = workspace()->stackingOrder().constEnd();
0691         while (it != end) {
0692             if (*it == this) {
0693                 detail = XCB_STACK_MODE_ABOVE;
0694                 break;
0695             } else if (*it == other) {
0696                 detail = XCB_STACK_MODE_BELOW;
0697                 break;
0698             }
0699             ++it;
0700         }
0701     } else if (detail == XCB_STACK_MODE_TOP_IF) {
0702         other = workspace()->findClient(Predicate::WindowMatch, above);
0703         if (other && other->frameGeometry().intersects(frameGeometry())) {
0704             workspace()->raiseWindowRequest(this, src, timestamp);
0705         }
0706         return;
0707     } else if (detail == XCB_STACK_MODE_BOTTOM_IF) {
0708         other = workspace()->findClient(Predicate::WindowMatch, above);
0709         if (other && other->frameGeometry().intersects(frameGeometry())) {
0710             workspace()->lowerWindowRequest(this, src, timestamp);
0711         }
0712         return;
0713     }
0714 
0715     if (!other) {
0716         other = workspace()->findClient(Predicate::WindowMatch, above);
0717     }
0718 
0719     if (other && detail == XCB_STACK_MODE_ABOVE) {
0720         auto it = workspace()->stackingOrder().constEnd(),
0721              begin = workspace()->stackingOrder().constBegin();
0722         while (--it != begin) {
0723 
0724             if (*it == other) { // the other one is top on stack
0725                 it = begin; // invalidate
0726                 src = NET::FromTool; // force
0727                 break;
0728             }
0729             X11Window *window = qobject_cast<X11Window *>(*it);
0730 
0731             if (!window || !((*it)->isNormalWindow() && window->isShown() && (*it)->isOnCurrentDesktop() && (*it)->isOnCurrentActivity() && (*it)->isOnOutput(output()))) {
0732                 continue; // irrelevant windows
0733             }
0734 
0735             if (*(it - 1) == other) {
0736                 break; // "it" is the one above the target one, stack below "it"
0737             }
0738         }
0739 
0740         if (it != begin && (*(it - 1) == other)) {
0741             other = qobject_cast<X11Window *>(*it);
0742         } else {
0743             other = nullptr;
0744         }
0745     }
0746 
0747     if (other) {
0748         workspace()->restack(this, other);
0749     } else if (detail == XCB_STACK_MODE_BELOW) {
0750         workspace()->lowerWindowRequest(this, src, timestamp);
0751     } else if (detail == XCB_STACK_MODE_ABOVE) {
0752         workspace()->raiseWindowRequest(this, src, timestamp);
0753     }
0754 
0755     if (send_event) {
0756         sendSyntheticConfigureNotify();
0757     }
0758 }
0759 
0760 bool X11Window::belongsToDesktop() const
0761 {
0762     const auto members = group()->members();
0763     for (const X11Window *window : members) {
0764         if (window->isDesktop()) {
0765             return true;
0766         }
0767     }
0768     return false;
0769 }
0770 
0771 } // namespace