95 if (m_blockStackingUpdates > 0) {
96 if (propagate_new_windows) {
97 m_blockedPropagatingNewWindows =
true;
101 QList<Window *> new_stacking_order = constrainedStackingOrder();
102 bool changed = (force_restacking || new_stacking_order != stacking_order);
103 force_restacking =
false;
104 stacking_order = new_stacking_order;
105 if (changed || propagate_new_windows) {
106 propagateWindows(propagate_new_windows);
108 for (
int i = 0; i < stacking_order.size(); ++i) {
109 stacking_order[i]->setStackingOrder(i);
114 if (m_activeWindow) {
139void Workspace::propagateWindows(
bool propagate_new_windows)
146 QList<xcb_window_t> newWindowStack;
153 newWindowStack <<
rootInfo()->supportWindow();
157 newWindowStack << manual_overlays;
159 newWindowStack.reserve(newWindowStack.size() + 2 * stacking_order.size());
161 for (
int i = stacking_order.size() - 1; i >= 0; --i) {
162 X11Window *window = qobject_cast<X11Window *>(stacking_order.at(i));
163 if (!window || window->isUnmanaged() || window->hiddenPreview()) {
167 if (window->inputId()) {
169 newWindowStack << window->inputId();
172 newWindowStack << window->frameId();
178 for (
int i = stacking_order.size() - 1; i >= 0; --i) {
179 X11Window *window = qobject_cast<X11Window *>(stacking_order.at(i));
180 if (!window || window->isUnmanaged() || !window->hiddenPreview()) {
183 newWindowStack << window->frameId();
187 Q_ASSERT(newWindowStack.at(0) ==
rootInfo()->supportWindow());
188 Xcb::restackWindows(newWindowStack);
190 QList<xcb_window_t> cl;
191 if (propagate_new_windows) {
192 cl.reserve(manual_overlays.size() + m_windows.size());
193 for (
const auto win : std::as_const(manual_overlays)) {
196 for (
Window *window : std::as_const(m_windows)) {
197 X11Window *x11Window = qobject_cast<X11Window *>(window);
198 if (x11Window && !x11Window->isUnmanaged()) {
199 cl.push_back(x11Window->window());
202 rootInfo()->setClientList(cl.constData(), cl.size());
206 for (
auto it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it) {
207 X11Window *window = qobject_cast<X11Window *>(*it);
208 if (window && !window->isUnmanaged()) {
209 cl.push_back(window->window());
212 for (
const auto win : std::as_const(manual_overlays)) {
215 rootInfo()->setClientListStacking(cl.constData(), cl.size());
227 QList<Window *> list;
228 if (!unconstrained) {
229 list = stacking_order;
231 list = unconstrained_stacking_order;
233 for (
int i = list.size() - 1; i >= 0; --i) {
234 auto window = list.at(i);
235 if (!window->isClient() || window->isDeleted()) {
238 if (window->isOnDesktop(desktop) && window->isShown() && window->isOnCurrentActivity() && !window->isShade()) {
239 if (output && window->output() != output) {
245 if (window->wantsTabFocus() && !window->isSpecialWindow()) {
257 for (
int i = stacking_order.size() - 1; i >= 0; i--) {
258 auto window = stacking_order.at(i);
259 if (window->isDeleted()) {
262 if (window->isClient() && window->isOnDesktop(desktop) && window->isDesktop() && window->isShown()) {
267 for (
Window *window : std::as_const(stacking_order)) {
268 if (window->isDeleted()) {
271 if (window->isClient() && window->isOnDesktop(desktop) && window->isDesktop() && window->isShown()) {
289 if (window == topmost) {
299 qCWarning(KWIN_CORE) <<
"Workspace::lowerWindow: closed window" << window <<
"cannot be restacked";
307 unconstrained_stacking_order.removeAll(window);
308 unconstrained_stacking_order.prepend(window);
311 QList<X11Window *> wins;
312 if (
auto group = window->
group()) {
315 for (
int i = wins.size() - 1; i >= 0; --i) {
316 if (wins[i] != window) {
323void Workspace::lowerWindowWithinApplication(
Window *window)
326 qCWarning(KWIN_CORE) <<
"Workspace::lowerWindowWithinApplication: closed window" << window <<
"cannot be restacked";
334 unconstrained_stacking_order.removeAll(window);
335 bool lowered =
false;
337 for (
auto it = unconstrained_stacking_order.begin(); it != unconstrained_stacking_order.end(); ++it) {
339 if (!other->isClient() || other->isDeleted()) {
343 unconstrained_stacking_order.insert(it, window);
349 unconstrained_stacking_order.prepend(window);
357 qCWarning(KWIN_CORE) <<
"Workspace::raiseWindow: closed window" << window <<
"cannot be restacked";
366 QList<Window *> transients;
367 Window *transient_parent = window;
368 while ((transient_parent = transient_parent->
transientFor())) {
369 transients.prepend(transient_parent);
371 for (
const auto &transient_parent : std::as_const(transients)) {
376 unconstrained_stacking_order.removeAll(window);
377 unconstrained_stacking_order.append(window);
380void Workspace::raiseWindowWithinApplication(
Window *window)
383 qCWarning(KWIN_CORE) <<
"Workspace::raiseWindowWithinApplication: closed window" << window <<
"cannot be restacked";
393 for (
int i = unconstrained_stacking_order.size() - 1; i > -1; --i) {
394 auto other = unconstrained_stacking_order.at(i);
395 if (!other->isClient() || other->isDeleted()) {
398 if (other == window) {
402 unconstrained_stacking_order.removeAll(window);
403 unconstrained_stacking_order.insert(unconstrained_stacking_order.indexOf(other) + 1, window);
411 if (src == NET::FromTool || allowFullClientRaising(window, timestamp)) {
414 raiseWindowWithinApplication(window);
428 lowerWindowWithinApplication(window);
434 lowerWindowWithinApplication(window);
440 qCWarning(KWIN_CORE) <<
"Workspace::restack: closed window" << window <<
"cannot be restacked";
443 Q_ASSERT(unconstrained_stacking_order.contains(under));
446 for (
int i = 0; i < unconstrained_stacking_order.size(); ++i) {
447 auto other = unconstrained_stacking_order.at(i);
449 under = (window == other) ?
nullptr : other;
455 unconstrained_stacking_order.removeAll(window);
456 unconstrained_stacking_order.insert(unconstrained_stacking_order.indexOf(under), window);
459 Q_ASSERT(unconstrained_stacking_order.contains(window));
460 m_focusChain->moveAfterWindow(window, under);
466 if (!m_activeWindow || m_activeWindow == window || m_activeWindow->
layer() != window->
layer()) {
470 restack(window, m_activeWindow);
479 unconstrained_stacking_order.removeAll(window);
480 for (
auto it = unconstrained_stacking_order.begin(); it != unconstrained_stacking_order.end(); ++it) {
481 X11Window *current = qobject_cast<X11Window *>(*it);
486 unconstrained_stacking_order.insert(it, window);
490 unconstrained_stacking_order.append(window);
502 if (
const Group *group = window->
group()) {
503 const auto members = group->members();
504 for (
const X11Window *member : members) {
505 if (member == window) {
507 }
else if (member->output() != window->
output()) {
521 if (
auto x11Window = qobject_cast<const X11Window *>(window)) {
522 return layerForWindow(x11Window);
524 return window->layer();
531QList<Window *> Workspace::constrainedStackingOrder()
536 for (
Window *window : std::as_const(unconstrained_stacking_order)) {
537 const Layer layer = computeLayer(window);
541 QList<Window *> stacking;
542 stacking.reserve(unconstrained_stacking_order.count());
549 QList<Constraint *> constraints;
550 constraints.reserve(m_constraints.count());
551 for (
Constraint *constraint : std::as_const(m_constraints)) {
552 if (constraint->parents.isEmpty()) {
553 constraint->enqueued =
true;
554 constraints.append(constraint);
556 constraint->enqueued =
false;
562 return stacking.indexOf(a->above) > stacking.indexOf(b->above);
564 std::sort(constraints.begin(), constraints.end(), constraintComparator);
569 while (!constraints.isEmpty()) {
570 Constraint *constraint = constraints.takeFirst();
572 const int belowIndex = stacking.indexOf(constraint->below);
573 const int aboveIndex = stacking.indexOf(constraint->above);
574 if (belowIndex == -1 || aboveIndex == -1) {
576 }
else if (aboveIndex < belowIndex) {
577 stacking.removeAt(aboveIndex);
578 stacking.insert(belowIndex, constraint->above);
582 QList<Constraint *> children = constraint->children;
583 std::sort(children.begin(), children.end(), constraintComparator);
585 for (
Constraint *child : std::as_const(children)) {
586 if (!child->enqueued) {
587 child->enqueued =
true;
588 constraints.append(child);
596void Workspace::blockStackingUpdates(
bool block)
599 if (m_blockStackingUpdates == 0) {
600 m_blockedPropagatingNewWindows =
false;
602 ++m_blockStackingUpdates;
604 if (--m_blockStackingUpdates == 0) {
615QList<T *> ensureStackingOrderInList(
const QList<Window *> &stackingOrder,
const QList<T *> &list)
617 static_assert(std::is_base_of<Window, T>::value,
618 "U must be derived from T");
620 if (list.count() < 2) {
624 QList<T *> result = list;
625 for (
auto it = stackingOrder.begin(); it != stackingOrder.end(); ++it) {
626 T *window = qobject_cast<T *>(*it);
630 if (result.removeAll(window) != 0) {
631 result.append(window);
641 return ensureStackingOrderInList(stacking_order, list);
646 return ensureStackingOrderInList(stacking_order, list);
651 return unconstrained_stacking_order;
654void Workspace::updateXStackingOrder()
657 Xcb::Tree tree(kwinApp()->x11RootWindow());
658 xcb_window_t *
windows = tree.children();
660 const auto count = tree.data()->children_len;
661 bool changed =
false;
662 for (
unsigned int i = 0; i < count; ++i) {
665 unconstrained_stacking_order.removeAll(window);
666 unconstrained_stacking_order.append(window);
683 if (detail == XCB_STACK_MODE_OPPOSITE) {
693 detail = XCB_STACK_MODE_ABOVE;
695 }
else if (*it == other) {
696 detail = XCB_STACK_MODE_BELOW;
701 }
else if (detail == XCB_STACK_MODE_TOP_IF) {
707 }
else if (detail == XCB_STACK_MODE_BOTTOM_IF) {
719 if (other && detail == XCB_STACK_MODE_ABOVE) {
722 while (--it != begin) {
731 if (!
window || !((*it)->isNormalWindow() &&
window->isShown() && (*it)->isOnCurrentDesktop() && (*it)->isOnCurrentActivity() && (*it)->isOnOutput(
output()))) {
735 if (*(it - 1) == other) {
740 if (it != begin && (*(it - 1) == other)) {
741 other = qobject_cast<X11Window *>(*it);
749 }
else if (detail == XCB_STACK_MODE_BELOW) {
751 }
else if (detail == XCB_STACK_MODE_ABOVE) {
756 sendSyntheticConfigureNotify();
764 if (
window->isDesktop()) {
void checkInputWindowStacking()
const QList< X11Window * > & members() const
bool isSeparateScreenFocus() const
QList< xcb_window_t > windows() const
virtual void updateMouseGrab()
virtual bool isTransient() const
static bool belongToSameApplication(const Window *c1, const Window *c2, SameApplicationChecks checks=SameApplicationChecks())
void demandAttention(bool set=true)
bool isOnCurrentDesktop() const
KWin::Window * transientFor
virtual const Group * group() const
X11Window * findUnmanaged(std::function< bool(const X11Window *)> func) const
ScreenEdges * screenEdges() const
void lowerWindowRequest(X11Window *window, NET::RequestSource src, xcb_timestamp_t timestamp)
X11Window * findClient(std::function< bool(const X11Window *)> func) const
Finds the first Client matching the condition expressed by passed in func.
const QList< Window * > & stackingOrder() const
void raiseWindowRequest(Window *window, NET::RequestSource src=NET::FromApplication, xcb_timestamp_t timestamp=0)
void stackScreenEdgesUnderOverrideRedirect()
void stackingOrderChanged()
Window * findDesktop(bool topmost, VirtualDesktop *desktop) const
friend Workspace * workspace()
void restack(Window *window, Window *under, bool force=false)
void updateStackingOrder(bool propagate_new_windows=false)
void raiseWindow(Window *window, bool nogroup=false)
Window * topWindowOnDesktop(VirtualDesktop *desktop, Output *output=nullptr, bool unconstrained=false, bool only_normal=true) const
QList< Window * > unconstrainedStackingOrder() const
void lowerWindow(Window *window, bool nogroup=false)
const QList< Window * > windows() const
friend class StackingUpdatesBlocker
void restoreSessionStackingOrder(X11Window *window)
void restackWindowUnderActive(Window *window)
void raiseOrLowerWindow(Window *window)
QList< X11Window * > ensureStackingOrder(const QList< X11Window * > &windows) const
bool hasUserTimeSupport() const
int sessionStackingOrder() const
void restackWindow(xcb_window_t above, int detail, NET::RequestSource source, xcb_timestamp_t timestamp, bool send_event=false)
bool belongsToDesktop() const override
bool isUnmanaged() const override
xcb_window_t window() const
const Group * group() const override