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