not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kwin / layers.cpp
blob7d85d73c8f5c7dcb8c906fb4b0662bcfb34ecd47
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
22 // SELI zmenit doc
26 This file contains things relevant to stacking order and layers.
28 Design:
30 Normal unconstrained stacking order, as requested by the user (by clicking
31 on windows to raise them, etc.), is in Workspace::unconstrained_stacking_order.
32 That list shouldn't be used at all, except for building
33 Workspace::stacking_order. The building is done
34 in Workspace::constrainedStackingOrder(). Only Workspace::stackingOrder() should
35 be used to get the stacking order, because it also checks the stacking order
36 is up to date.
37 All clients are also stored in Workspace::clients (except for isDesktop() clients,
38 as those are very special, and are stored in Workspace::desktops), in the order
39 the clients were created.
41 Every window has one layer assigned in which it is. There are 6 layers,
42 from bottom : DesktopLayer, BelowLayer, NormalLayer, DockLayer, AboveLayer
43 and ActiveLayer (see also NETWM sect.7.10.). The layer a window is in depends
44 on the window type, and on other things like whether the window is active.
46 NET::Splash clients belong to the Normal layer. NET::TopMenu clients
47 belong to Dock layer. Clients that are both NET::Dock and NET::KeepBelow
48 are in the Normal layer in order to keep the 'allow window to cover
49 the panel' Kicker setting to work as intended (this may look like a slight
50 spec violation, but a) I have no better idea, b) the spec allows adjusting
51 the stacking order if the WM thinks it's a good idea . We put all
52 NET::KeepAbove above all Docks too, even though the spec suggests putting
53 them in the same layer.
55 Most transients are in the same layer as their mainwindow,
56 see Workspace::constrainedStackingOrder(), they may also be in higher layers, but
57 they should never be below their mainwindow.
59 When some client attribute changes (above/below flag, transiency...),
60 Workspace::updateClientLayer() should be called in order to make
61 sure it's moved to the appropriate layer ClientList if needed.
63 Currently the things that affect client in which layer a client
64 belongs: KeepAbove/Keep Below flags, window type, fullscreen
65 state and whether the client is active, mainclient (transiency).
67 Make sure updateStackingOrder() is called in order to make
68 Workspace::stackingOrder() up to date and propagated to the world.
69 Using Workspace::blockStackingUpdates() (or the StackingUpdatesBlocker
70 helper class) it's possible to temporarily disable updates
71 and the stacking order will be updated once after it's allowed again.
75 #include <assert.h>
77 #include <kdebug.h>
79 #include "utils.h"
80 #include "client.h"
81 #include "workspace.h"
82 #include "tabbox.h"
83 #include "group.h"
84 #include "rules.h"
85 #include "unmanaged.h"
86 #include "deleted.h"
87 #include <QX11Info>
89 namespace KWin
92 //*******************************
93 // Workspace
94 //*******************************
96 void Workspace::updateClientLayer( Client* c )
98 if( c == NULL )
99 return;
100 if( c->layer() == c->belongsToLayer())
101 return;
102 StackingUpdatesBlocker blocker( this );
103 c->invalidateLayer(); // invalidate, will be updated when doing restacking
104 for( ClientList::ConstIterator it = c->transients().constBegin();
105 it != c->transients().constEnd();
106 ++it )
107 updateClientLayer( *it );
110 void Workspace::updateStackingOrder( bool propagate_new_clients )
112 if( block_stacking_updates > 0 )
114 if( propagate_new_clients )
115 blocked_propagating_new_clients = true;
116 return;
118 ClientList new_stacking_order = constrainedStackingOrder();
119 bool changed = ( new_stacking_order != stacking_order || force_restacking );
120 force_restacking = false;
121 stacking_order = new_stacking_order;
122 #if 0
123 kDebug(1212) << "stacking:" << changed;
124 if( changed || propagate_new_clients )
126 for( ClientList::ConstIterator it = stacking_order.begin();
127 it != stacking_order.end();
128 ++it )
129 kDebug(1212) << (void*)(*it) << *it << ":" << (*it)->layer();
131 #endif
132 if( changed || propagate_new_clients )
134 propagateClients( propagate_new_clients );
135 addRepaintFull();
136 if( active_client )
137 active_client->updateMouseGrab();
142 Propagates the managed clients to the world.
143 Called ONLY from updateStackingOrder().
145 void Workspace::propagateClients( bool propagate_new_clients )
147 Window *cl; // MW we should not assume WId and Window to be compatible
148 // when passig pointers around.
150 // restack the windows according to the stacking order
151 // 1 - supportWindow, 1 - topmenu_space, 8 - electric borders
152 Window* new_stack = new Window[ stacking_order.count() + 1 + 1 + 8 ];
153 int pos = 0;
154 // Stack all windows under the support window. The support window is
155 // not used for anything (besides the NETWM property), and it's not shown,
156 // but it was lowered after kwin startup. Stacking all clients below
157 // it ensures that no client will be ever shown above override-redirect
158 // windows (e.g. popups).
159 new_stack[ pos++ ] = supportWindow->winId();
160 for( int i = 0;
161 i < ELECTRIC_COUNT;
162 ++i )
163 if( electric_windows[ i ] != None )
164 new_stack[ pos++ ] = electric_windows[ i ];
165 int topmenu_space_pos = 1; // not 0, that's supportWindow !!!
166 for ( int i = stacking_order.size() - 1; i >= 0; i-- )
168 if( stacking_order.at( i )->hiddenPreview())
169 continue;
170 new_stack[ pos++ ] = stacking_order.at( i )->frameId();
171 if( stacking_order.at( i )->belongsToLayer() >= DockLayer )
172 topmenu_space_pos = pos;
174 if( topmenu_space != NULL )
175 { // make sure the topmenu space is below all topmenus, fullscreens, etc.
176 for( int i = pos;
177 i > topmenu_space_pos;
178 --i )
179 new_stack[ i ] = new_stack[ i - 1 ];
180 new_stack[ topmenu_space_pos ] = topmenu_space->winId();
181 ++pos;
183 // when having hidden previews, stack hidden windows below everything else
184 // (as far as pure X stacking order is concerned), in order to avoid having
185 // these windows that should be unmapped to interfere with other windows
186 for ( int i = stacking_order.size() - 1; i >= 0; i-- )
188 if( !stacking_order.at( i )->hiddenPreview())
189 continue;
190 new_stack[ pos++ ] = stacking_order.at( i )->frameId();
191 if( stacking_order.at( i )->belongsToLayer() >= DockLayer )
192 topmenu_space_pos = pos;
194 // TODO isn't it too inefficient to restack always all clients?
195 // TODO don't restack not visible windows?
196 assert( new_stack[ 0 ] == supportWindow->winId());
197 XRestackWindows(display(), new_stack, pos);
198 delete [] new_stack;
200 if ( propagate_new_clients )
202 cl = new Window[ desktops.count() + clients.count()];
203 pos = 0;
204 // TODO this is still not completely in the map order
205 for ( ClientList::ConstIterator it = desktops.constBegin(); it != desktops.constEnd(); ++it )
206 cl[pos++] = (*it)->window();
207 for ( ClientList::ConstIterator it = clients.constBegin(); it != clients.constEnd(); ++it )
208 cl[pos++] = (*it)->window();
209 rootInfo->setClientList( cl, pos );
210 delete [] cl;
213 cl = new Window[ stacking_order.count()];
214 pos = 0;
215 for ( ClientList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it)
216 cl[pos++] = (*it)->window();
217 rootInfo->setClientListStacking( cl, pos );
218 delete [] cl;
220 // Make the cached stacking order invalid here, in case we need the new stacking order before we get
221 // the matching event, due to X being asynchronous.
222 x_stacking_dirty = true;
227 Returns topmost visible client. Windows on the dock, the desktop
228 or of any other special kind are excluded. Also if the window
229 doesn't accept focus it's excluded.
231 // TODO misleading name for this method, too many slightly different ways to use it
232 Client* Workspace::topClientOnDesktop( int desktop, int screen, bool unconstrained, bool only_normal ) const
234 // TODO Q_ASSERT( block_stacking_updates == 0 );
235 ClientList list;
236 if( !unconstrained )
237 list = stacking_order;
238 else
239 list = unconstrained_stacking_order;
240 for( int i = list.size() - 1;
241 i >= 0;
242 --i )
244 if( list.at( i )->isOnDesktop( desktop ) && list.at( i )->isShown( false ))
246 if( screen != -1 && list.at( i )->screen() != screen )
247 continue;
248 if( !only_normal )
249 return list.at( i );
250 if( list.at( i )->wantsTabFocus() && !list.at( i )->isSpecialWindow())
251 return list.at( i );
254 return 0;
257 Client* Workspace::findDesktop( bool topmost, int desktop ) const
259 // TODO Q_ASSERT( block_stacking_updates == 0 );
260 if( topmost )
262 for ( int i = stacking_order.size() - 1; i>=0; i-- )
264 if ( stacking_order.at( i )->isOnDesktop( desktop ) && stacking_order.at( i )->isDesktop()
265 && stacking_order.at( i )->isShown( true ))
266 return stacking_order.at( i );
269 else // bottom-most
271 foreach ( Client* c, stacking_order )
273 if ( c->isOnDesktop( desktop ) && c->isDesktop()
274 && c->isShown( true ))
275 return c;
278 return NULL;
281 void Workspace::raiseOrLowerClient( Client *c)
283 if (!c) return;
284 Client* topmost = NULL;
285 // TODO Q_ASSERT( block_stacking_updates == 0 );
286 if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
287 most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
288 topmost = most_recently_raised;
289 else
290 topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop(),
291 options->separateScreenFocus ? c->screen() : -1 );
293 if( c == topmost)
294 lowerClient(c);
295 else
296 raiseClient(c);
300 void Workspace::lowerClient( Client* c, bool nogroup )
302 if ( !c )
303 return;
304 if( c->isTopMenu())
305 return;
307 c->cancelAutoRaise();
309 StackingUpdatesBlocker blocker( this );
311 unconstrained_stacking_order.removeAll( c );
312 unconstrained_stacking_order.prepend( c );
313 if( !nogroup && c->isTransient() )
315 // lower also all windows in the group, in their reversed stacking order
316 ClientList wins = ensureStackingOrder( c->group()->members());
317 for( int i = wins.size() - 1;
318 i >= 0;
319 --i )
321 if( wins[ i ] != c )
322 lowerClient( wins[ i ], true );
326 if ( c == most_recently_raised )
327 most_recently_raised = 0;
330 void Workspace::lowerClientWithinApplication( Client* c )
332 if ( !c )
333 return;
334 if( c->isTopMenu())
335 return;
337 c->cancelAutoRaise();
339 StackingUpdatesBlocker blocker( this );
341 unconstrained_stacking_order.removeAll( c );
342 bool lowered = false;
343 // first try to put it below the bottom-most window of the application
344 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
345 it != unconstrained_stacking_order.end();
346 ++it )
347 if( Client::belongToSameApplication( *it, c ))
349 unconstrained_stacking_order.insert( it, c );
350 lowered = true;
351 break;
353 if( !lowered )
354 unconstrained_stacking_order.prepend( c );
355 // ignore mainwindows
358 void Workspace::raiseClient( Client* c, bool nogroup )
360 if ( !c )
361 return;
362 if( c->isTopMenu())
363 return;
365 c->cancelAutoRaise();
367 StackingUpdatesBlocker blocker( this );
369 if( !nogroup && c->isTransient())
371 ClientList wins = ensureStackingOrder( c->group()->members());
372 foreach( Client* c2, wins )
373 if( c2 != c )
374 raiseClient( c2, true );
377 unconstrained_stacking_order.removeAll( c );
378 unconstrained_stacking_order.append( c );
380 if( !c->isSpecialWindow())
382 most_recently_raised = c;
383 pending_take_activity = NULL;
387 void Workspace::raiseClientWithinApplication( Client* c )
389 if ( !c )
390 return;
391 if( c->isTopMenu())
392 return;
394 c->cancelAutoRaise();
396 StackingUpdatesBlocker blocker( this );
397 // ignore mainwindows
399 // first try to put it above the top-most window of the application
400 for ( int i = unconstrained_stacking_order.size() - 1; i>= 0 ; i-- )
402 if( unconstrained_stacking_order.at( i ) == c ) // don't lower it just because it asked to be raised
403 return;
404 if( Client::belongToSameApplication( unconstrained_stacking_order.at( i ), c ))
406 unconstrained_stacking_order.removeAll( c );
407 unconstrained_stacking_order.insert( ++i, c ); // insert after the found one
408 return;
413 void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp )
415 if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
416 raiseClient( c );
417 else
419 raiseClientWithinApplication( c );
420 c->demandAttention();
424 void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time /*timestamp*/ )
426 // If the client has support for all this focus stealing prevention stuff,
427 // do only lowering within the application, as that's the more logical
428 // variant of lowering when application requests it.
429 // No demanding of attention here of course.
430 if( src == NET::FromTool || !c->hasUserTimeSupport())
431 lowerClient( c );
432 else
433 lowerClientWithinApplication( c );
436 void Workspace::restackClientUnderActive( Client* c )
438 if( c->isTopMenu())
439 return;
440 if( !active_client || active_client == c )
442 raiseClient( c );
443 return;
446 assert( unconstrained_stacking_order.contains( active_client ));
447 if( Client::belongToSameApplication( active_client, c ))
448 { // put it below the active window if it's the same app
449 unconstrained_stacking_order.removeAll( c );
450 unconstrained_stacking_order.insert( unconstrained_stacking_order.indexOf( active_client ), c );
452 else
453 { // put in the stacking order below _all_ windows belonging to the active application
454 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
455 it != unconstrained_stacking_order.end();
456 ++it )
457 { // TODO ignore topmenus?
458 if( Client::belongToSameApplication( active_client, *it ))
460 if( *it != c )
462 unconstrained_stacking_order.removeAll( c );
463 unconstrained_stacking_order.insert( it, c );
465 break;
469 assert( unconstrained_stacking_order.contains( c ));
470 for( int desktop = 1;
471 desktop <= numberOfDesktops();
472 ++desktop )
473 { // do for every virtual desktop to handle the case of onalldesktop windows
474 if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client ))
476 if( Client::belongToSameApplication( active_client, c ))
477 { // put it after the active window if it's the same app
478 focus_chain[ desktop ].removeAll( c );
479 focus_chain[ desktop ].insert( focus_chain[ desktop ].indexOf( active_client ), c );
481 else
482 { // put it in focus_chain[currentDesktop()] after all windows belonging to the active applicationa
483 focus_chain[ desktop ].removeAll( c );
484 for( int i = focus_chain[ desktop ].size() - 1;
485 i >= 0;
486 --i )
488 if( Client::belongToSameApplication( active_client, focus_chain[ desktop ].at( i )))
490 focus_chain[ desktop ].insert( i, c );
491 break;
497 // the same for global_focus_chain
498 if( c->wantsTabFocus() && global_focus_chain.contains( active_client ))
500 if( Client::belongToSameApplication( active_client, c ))
502 global_focus_chain.removeAll( c );
503 global_focus_chain.insert( global_focus_chain.indexOf( active_client ), c );
505 else
507 global_focus_chain.removeAll( c );
508 for ( int i = global_focus_chain.size() - 1;
509 i >= 0;
510 --i )
512 if( Client::belongToSameApplication( active_client, global_focus_chain.at( i ) ))
514 global_focus_chain.insert( i, c );
515 break;
520 updateStackingOrder();
523 void Workspace::restoreSessionStackingOrder( Client* c )
525 if( c->sessionStackingOrder() < 0 )
526 return;
527 StackingUpdatesBlocker blocker( this );
528 unconstrained_stacking_order.removeAll( c );
529 ClientList::Iterator best_pos = unconstrained_stacking_order.end();
530 for( ClientList::Iterator it = unconstrained_stacking_order.begin(); // from bottom
531 it != unconstrained_stacking_order.end();
532 ++it )
534 if( (*it)->sessionStackingOrder() > c->sessionStackingOrder() )
536 unconstrained_stacking_order.insert( it, c );
537 return;
540 unconstrained_stacking_order.append( c );
543 void Workspace::circulateDesktopApplications()
545 if ( desktops.count() > 1 )
547 bool change_active = activeClient()->isDesktop();
548 raiseClient( findDesktop( false, currentDesktop()));
549 if( change_active ) // if the previously topmost Desktop was active, activate this new one
550 activateClient( findDesktop( true, currentDesktop()));
552 // if there's no active client, make desktop the active one
553 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
554 activateClient( findDesktop( true, currentDesktop()));
559 Returns a stacking order based upon \a list that fulfills certain contained.
561 ClientList Workspace::constrainedStackingOrder()
563 ClientList layer[ NumLayers ];
565 #if 0
566 kDebug(1212) << "stacking1:";
567 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
568 it != unconstrained_stacking_order.end();
569 ++it )
570 kDebug(1212) << (void*)(*it) << *it << ":" << (*it)->layer();
571 #endif
572 // build the order from layers
573 QHash< Group*, Layer > minimum_layer;
574 for( ClientList::ConstIterator it = unconstrained_stacking_order.constBegin();
575 it != unconstrained_stacking_order.constEnd();
576 ++it )
578 Layer l = (*it)->layer();
579 // If a window is raised above some other window in the same window group
580 // which is in the ActiveLayer (i.e. it's fulscreened), make sure it stays
581 // above that window (see #95731).
582 if( minimum_layer.contains( (*it)->group())
583 && minimum_layer[ (*it)->group() ] == ActiveLayer
584 && ( l == NormalLayer || l == AboveLayer ))
586 l = minimum_layer[ (*it)->group() ];
588 minimum_layer[ (*it)->group() ] = l;
589 layer[ l ].append( *it );
591 ClientList stacking;
592 for( Layer lay = FirstLayer;
593 lay < NumLayers;
594 ++lay )
595 stacking += layer[ lay ];
596 #if 0
597 kDebug(1212) << "stacking2:";
598 for( ClientList::ConstIterator it = stacking.begin();
599 it != stacking.end();
600 ++it )
601 kDebug(1212) << (void*)(*it) << *it << ":" << (*it)->layer();
602 #endif
603 // now keep transients above their mainwindows
604 // TODO this could(?) use some optimization
605 for( int i = stacking.size() - 1;
606 i >= 0;
609 if( !stacking[ i ]->isTransient())
611 --i;
612 continue;
614 int i2 = -1;
615 if( stacking[ i ]->groupTransient())
617 if( stacking[ i ]->group()->members().count() > 0 )
618 { // find topmost client this one is transient for
619 for( i2 = stacking.size() - 1;
620 i2 >= 0;
621 --i2 )
623 if( stacking[ i2 ] == stacking[ i ] )
625 i2 = -1; // don't reorder, already the topmost in the group
626 break;
628 if( stacking[ i2 ]->hasTransient( stacking[ i ], true )
629 && keepTransientAbove( stacking[ i2 ], stacking[ i ] ))
630 break;
632 } // else i2 remains pointing at -1
634 else
636 for( i2 = stacking.size() - 1;
637 i2 >= 0;
638 --i2 )
640 if( stacking[ i2 ] == stacking[ i ] )
642 i2 = -1; // don't reorder, already on top of its mainwindow
643 break;
645 if( stacking[ i2 ] == stacking[ i ]->transientFor()
646 && keepTransientAbove( stacking[ i2 ], stacking[ i ] ))
647 break;
650 if( i2 == -1 )
652 --i;
653 continue;
655 Client* current = stacking[ i ];
656 stacking.removeAt( i );
657 --i; // move onto the next item (for next for() iteration)
658 --i2; // adjust index of the mainwindow after the remove above
659 if( !current->transients().isEmpty()) // this one now can be possibly above its transients,
660 i = i2; // so go again higher in the stack order and possibly move those transients again
661 ++i2; // insert after (on top of) the mainwindow, it's ok if it2 is now stacking.end()
662 stacking.insert( i2, current );
664 #if 0
665 kDebug(1212) << "stacking3:";
666 for( ClientList::ConstIterator it = stacking.begin();
667 it != stacking.end();
668 ++it )
669 kDebug(1212) << (void*)(*it) << *it << ":" << (*it)->layer();
670 kDebug(1212) << "\n\n";
671 #endif
672 return stacking;
675 void Workspace::blockStackingUpdates( bool block )
677 if( block )
679 if( block_stacking_updates == 0 )
680 blocked_propagating_new_clients = false;
681 ++block_stacking_updates;
683 else // !block
684 if( --block_stacking_updates == 0 )
685 updateStackingOrder( blocked_propagating_new_clients );
688 // Ensure list is in stacking order
689 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
691 // TODO Q_ASSERT( block_stacking_updates == 0 );
692 if( list.count() < 2 )
693 return list;
694 // TODO is this worth optimizing?
695 ClientList result = list;
696 for( ClientList::ConstIterator it = stacking_order.constBegin();
697 it != stacking_order.constEnd();
698 ++it )
699 if( result.removeAll( *it ) != 0 )
700 result.append( *it );
701 return result;
704 // check whether a transient should be actually kept above its mainwindow
705 // there may be some special cases where this rule shouldn't be enfored
706 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
708 // When topmenu's mainwindow becomes active, topmenu is raised and shown.
709 // They also belong to the Dock layer. This makes them to be very high.
710 // Therefore don't keep group transients above them, otherwise this would move
711 // group transients way too high.
712 if( mainwindow->isTopMenu() && transient->groupTransient())
713 return false;
714 // #93832 - don't keep splashscreens above dialogs
715 if( transient->isSplash() && mainwindow->isDialog())
716 return false;
717 // This is rather a hack for #76026. Don't keep non-modal dialogs above
718 // the mainwindow, but only if they're group transient (since only such dialogs
719 // have taskbar entry in Kicker). A proper way of doing this (both kwin and kicker)
720 // needs to be found.
721 if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
722 return false;
723 // #63223 - don't keep transients above docks, because the dock is kept high,
724 // and e.g. dialogs for them would be too high too
725 if( mainwindow->isDock())
726 return false;
727 return true;
730 // Returns all windows in their stacking order on the root window.
731 ToplevelList Workspace::xStackingOrder() const
733 if( !x_stacking_dirty )
734 return x_stacking;
735 x_stacking_dirty = false;
736 x_stacking.clear();
737 Window dummy;
738 Window* windows = NULL;
739 unsigned int count = 0;
740 XQueryTree( display(), rootWindow(), &dummy, &dummy, &windows, &count );
741 // use our own stacking order, not the X one, as they may differ
742 foreach( Client* c, stacking_order )
743 x_stacking.append( c );
744 for( unsigned int i = 0;
745 i < count;
746 ++i )
748 if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( windows[ i ] )))
749 x_stacking.append( c );
751 foreach( Deleted* c, deleted )
752 x_stacking.append( c );
753 if( windows != NULL )
754 XFree( windows );
755 const_cast< Workspace* >( this )->checkUnredirect();
756 return x_stacking;
759 //*******************************
760 // Client
761 //*******************************
763 void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event )
765 switch ( detail )
767 case Above:
768 case TopIf:
769 workspace()->raiseClientRequest( this, src, timestamp );
770 break;
771 case Below:
772 case BottomIf:
773 workspace()->lowerClientRequest( this, src, timestamp );
774 break;
775 case Opposite:
776 default:
777 break;
779 if( send_event )
780 sendSyntheticConfigureNotify();
783 void Client::setKeepAbove( bool b )
785 b = rules()->checkKeepAbove( b );
786 if( b && !rules()->checkKeepBelow( false ))
787 setKeepBelow( false );
788 if ( b == keepAbove())
789 { // force hint change if different
790 if( bool( info->state() & NET::KeepAbove ) != keepAbove())
791 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
792 return;
794 keep_above = b;
795 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
796 if( decoration != NULL )
797 decoration->emitKeepAboveChanged( keepAbove());
798 workspace()->updateClientLayer( this );
799 updateWindowRules();
802 void Client::setKeepBelow( bool b )
804 b = rules()->checkKeepBelow( b );
805 if( b && !rules()->checkKeepAbove( false ))
806 setKeepAbove( false );
807 if ( b == keepBelow())
808 { // force hint change if different
809 if( bool( info->state() & NET::KeepBelow ) != keepBelow())
810 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
811 return;
813 keep_below = b;
814 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
815 if( decoration != NULL )
816 decoration->emitKeepBelowChanged( keepBelow());
817 workspace()->updateClientLayer( this );
818 updateWindowRules();
821 Layer Client::layer() const
823 if( in_layer == UnknownLayer )
824 const_cast< Client* >( this )->in_layer = belongsToLayer();
825 return in_layer;
828 Layer Client::belongsToLayer() const
830 if( isDesktop())
831 return DesktopLayer;
832 if( isSplash()) // no damn annoying splashscreens
833 return NormalLayer; // getting in the way of everything else
834 if( isDock() && keepBelow())
835 // slight hack for the 'allow window to cover panel' Kicker setting
836 // don't move keepbelow docks below normal window, but only to the same
837 // layer, so that both may be raised to cover the other
838 return NormalLayer;
839 if( keepBelow())
840 return BelowLayer;
841 if( isDock() && !keepBelow())
842 return DockLayer;
843 if( isTopMenu())
844 return DockLayer;
845 if( isActiveFullScreen())
846 return ActiveLayer;
847 if( keepAbove())
848 return AboveLayer;
849 return NormalLayer;
852 bool Client::isActiveFullScreen() const
854 // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
855 // i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
856 const Client* ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker
857 const Client* top = workspace()->topClientOnDesktop( workspace()->currentDesktop(), screen(), true, false );
858 return( isFullScreen() && ac != NULL && top != NULL
859 // not needed, for xinerama && ( ac == this || this->group() == ac->group())
860 && ( top == this || this->group() == top->group()));
863 } // namespace