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 *********************************************************************/
26 This file contains things relevant to stacking order and layers.
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
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.
81 #include "workspace.h"
85 #include "unmanaged.h"
92 //*******************************
94 //*******************************
96 void Workspace::updateClientLayer( Client
* c
)
100 if( c
->layer() == c
->belongsToLayer())
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();
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;
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
;
123 kDebug(1212) << "stacking:" << changed
;
124 if( changed
|| propagate_new_clients
)
126 for( ClientList::ConstIterator it
= stacking_order
.begin();
127 it
!= stacking_order
.end();
129 kDebug(1212) << (void*)(*it
) << *it
<< ":" << (*it
)->layer();
132 if( changed
|| propagate_new_clients
)
134 propagateClients( propagate_new_clients
);
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 ];
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();
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())
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.
177 i
> topmenu_space_pos
;
179 new_stack
[ i
] = new_stack
[ i
- 1 ];
180 new_stack
[ topmenu_space_pos
] = topmenu_space
->winId();
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())
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
);
200 if ( propagate_new_clients
)
202 cl
= new Window
[ desktops
.count() + clients
.count()];
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
);
213 cl
= new Window
[ stacking_order
.count()];
215 for ( ClientList::ConstIterator it
= stacking_order
.constBegin(); it
!= stacking_order
.constEnd(); ++it
)
216 cl
[pos
++] = (*it
)->window();
217 rootInfo
->setClientListStacking( cl
, pos
);
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 );
237 list
= stacking_order
;
239 list
= unconstrained_stacking_order
;
240 for( int i
= list
.size() - 1;
244 if( list
.at( i
)->isOnDesktop( desktop
) && list
.at( i
)->isShown( false ))
246 if( screen
!= -1 && list
.at( i
)->screen() != screen
)
250 if( list
.at( i
)->wantsTabFocus() && !list
.at( i
)->isSpecialWindow())
257 Client
* Workspace::findDesktop( bool topmost
, int desktop
) const
259 // TODO Q_ASSERT( block_stacking_updates == 0 );
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
);
271 foreach ( Client
* c
, stacking_order
)
273 if ( c
->isOnDesktop( desktop
) && c
->isDesktop()
274 && c
->isShown( true ))
281 void Workspace::raiseOrLowerClient( Client
*c
)
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
;
290 topmost
= topClientOnDesktop( c
->isOnAllDesktops() ? currentDesktop() : c
->desktop(),
291 options
->separateScreenFocus
? c
->screen() : -1 );
300 void Workspace::lowerClient( Client
* c
, bool nogroup
)
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;
322 lowerClient( wins
[ i
], true );
326 if ( c
== most_recently_raised
)
327 most_recently_raised
= 0;
330 void Workspace::lowerClientWithinApplication( Client
* c
)
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();
347 if( Client::belongToSameApplication( *it
, c
))
349 unconstrained_stacking_order
.insert( it
, c
);
354 unconstrained_stacking_order
.prepend( c
);
355 // ignore mainwindows
358 void Workspace::raiseClient( Client
* c
, bool nogroup
)
365 c
->cancelAutoRaise();
367 StackingUpdatesBlocker
blocker( this );
369 if( !nogroup
&& c
->isTransient())
371 ClientList wins
= ensureStackingOrder( c
->group()->members());
372 foreach( Client
* c2
, wins
)
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
)
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
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
413 void Workspace::raiseClientRequest( Client
* c
, NET::RequestSource src
, Time timestamp
)
415 if( src
== NET::FromTool
|| allowFullClientRaising( c
, timestamp
))
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())
433 lowerClientWithinApplication( c
);
436 void Workspace::restackClientUnderActive( Client
* c
)
440 if( !active_client
|| active_client
== c
)
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
);
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();
457 { // TODO ignore topmenus?
458 if( Client::belongToSameApplication( active_client
, *it
))
462 unconstrained_stacking_order
.removeAll( c
);
463 unconstrained_stacking_order
.insert( it
, c
);
469 assert( unconstrained_stacking_order
.contains( c
));
470 for( int desktop
= 1;
471 desktop
<= numberOfDesktops();
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
);
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;
488 if( Client::belongToSameApplication( active_client
, focus_chain
[ desktop
].at( i
)))
490 focus_chain
[ desktop
].insert( i
, c
);
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
);
507 global_focus_chain
.removeAll( c
);
508 for ( int i
= global_focus_chain
.size() - 1;
512 if( Client::belongToSameApplication( active_client
, global_focus_chain
.at( i
) ))
514 global_focus_chain
.insert( i
, c
);
520 updateStackingOrder();
523 void Workspace::restoreSessionStackingOrder( Client
* c
)
525 if( c
->sessionStackingOrder() < 0 )
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();
534 if( (*it
)->sessionStackingOrder() > c
->sessionStackingOrder() )
536 unconstrained_stacking_order
.insert( it
, c
);
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
];
566 kDebug(1212) << "stacking1:";
567 for( ClientList::ConstIterator it
= unconstrained_stacking_order
.begin();
568 it
!= unconstrained_stacking_order
.end();
570 kDebug(1212) << (void*)(*it
) << *it
<< ":" << (*it
)->layer();
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();
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
);
592 for( Layer lay
= FirstLayer
;
595 stacking
+= layer
[ lay
];
597 kDebug(1212) << "stacking2:";
598 for( ClientList::ConstIterator it
= stacking
.begin();
599 it
!= stacking
.end();
601 kDebug(1212) << (void*)(*it
) << *it
<< ":" << (*it
)->layer();
603 // now keep transients above their mainwindows
604 // TODO this could(?) use some optimization
605 for( int i
= stacking
.size() - 1;
609 if( !stacking
[ i
]->isTransient())
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;
623 if( stacking
[ i2
] == stacking
[ i
] )
625 i2
= -1; // don't reorder, already the topmost in the group
628 if( stacking
[ i2
]->hasTransient( stacking
[ i
], true )
629 && keepTransientAbove( stacking
[ i2
], stacking
[ i
] ))
632 } // else i2 remains pointing at -1
636 for( i2
= stacking
.size() - 1;
640 if( stacking
[ i2
] == stacking
[ i
] )
642 i2
= -1; // don't reorder, already on top of its mainwindow
645 if( stacking
[ i2
] == stacking
[ i
]->transientFor()
646 && keepTransientAbove( stacking
[ i2
], stacking
[ i
] ))
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
);
665 kDebug(1212) << "stacking3:";
666 for( ClientList::ConstIterator it
= stacking
.begin();
667 it
!= stacking
.end();
669 kDebug(1212) << (void*)(*it
) << *it
<< ":" << (*it
)->layer();
670 kDebug(1212) << "\n\n";
675 void Workspace::blockStackingUpdates( bool block
)
679 if( block_stacking_updates
== 0 )
680 blocked_propagating_new_clients
= false;
681 ++block_stacking_updates
;
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 )
694 // TODO is this worth optimizing?
695 ClientList result
= list
;
696 for( ClientList::ConstIterator it
= stacking_order
.constBegin();
697 it
!= stacking_order
.constEnd();
699 if( result
.removeAll( *it
) != 0 )
700 result
.append( *it
);
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())
714 // #93832 - don't keep splashscreens above dialogs
715 if( transient
->isSplash() && mainwindow
->isDialog())
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())
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())
730 // Returns all windows in their stacking order on the root window.
731 ToplevelList
Workspace::xStackingOrder() const
733 if( !x_stacking_dirty
)
735 x_stacking_dirty
= false;
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;
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
)
755 const_cast< Workspace
* >( this )->checkUnredirect();
759 //*******************************
761 //*******************************
763 void Client::restackWindow( Window
/*above TODO */, int detail
, NET::RequestSource src
, Time timestamp
, bool send_event
)
769 workspace()->raiseClientRequest( this, src
, timestamp
);
773 workspace()->lowerClientRequest( this, src
, timestamp
);
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
);
795 info
->setState( keepAbove() ? NET::KeepAbove
: 0, NET::KeepAbove
);
796 if( decoration
!= NULL
)
797 decoration
->emitKeepAboveChanged( keepAbove());
798 workspace()->updateClientLayer( this );
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
);
814 info
->setState( keepBelow() ? NET::KeepBelow
: 0, NET::KeepBelow
);
815 if( decoration
!= NULL
)
816 decoration
->emitKeepBelowChanged( keepBelow());
817 workspace()->updateClientLayer( this );
821 Layer
Client::layer() const
823 if( in_layer
== UnknownLayer
)
824 const_cast< Client
* >( this )->in_layer
= belongsToLayer();
828 Layer
Client::belongsToLayer() const
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
841 if( isDock() && !keepBelow())
845 if( isActiveFullScreen())
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()));