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