summaryrefslogtreecommitdiffstats
path: root/kwin/layers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kwin/layers.cpp')
-rw-r--r--kwin/layers.cpp830
1 files changed, 0 insertions, 830 deletions
diff --git a/kwin/layers.cpp b/kwin/layers.cpp
deleted file mode 100644
index 773ea2d58..000000000
--- a/kwin/layers.cpp
+++ /dev/null
@@ -1,830 +0,0 @@
-/*****************************************************************
- KWin - the KDE window manager
- This file is part of the KDE project.
-
-Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
-Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
-
-You can Freely distribute this program under the GNU General Public
-License. See the file "COPYING" for the exact licensing terms.
-******************************************************************/
-
-// SELI zmenit doc
-
-/*
-
- This file contains things relevant to stacking order and layers.
-
- Design:
-
- Normal unconstrained stacking order, as requested by the user (by clicking
- on windows to raise them, etc.), is in Workspace::unconstrained_stacking_order.
- That list shouldn't be used at all, except for building
- Workspace::stacking_order. The building is done
- in Workspace::constrainedStackingOrder(). Only Workspace::stackingOrder() should
- be used to get the stacking order, because it also checks the stacking order
- is up to date.
- All clients are also stored in Workspace::clients (except for isDesktop() clients,
- as those are very special, and are stored in Workspace::desktops), in the order
- the clients were created.
-
- Every window has one layer assigned in which it is. There are 6 layers,
- from bottom : DesktopLayer, BelowLayer, NormalLayer, DockLayer, AboveLayer
- and ActiveLayer (see also NETWM sect.7.10.). The layer a window is in depends
- on the window type, and on other things like whether the window is active.
-
- NET::Splash clients belong to the Normal layer. NET::TopMenu clients
- belong to Dock layer. Clients that are both NET::Dock and NET::KeepBelow
- are in the Normal layer in order to keep the 'allow window to cover
- the panel' Kicker setting to work as intended (this may look like a slight
- spec violation, but a) I have no better idea, b) the spec allows adjusting
- the stacking order if the WM thinks it's a good idea . We put all
- NET::KeepAbove above all Docks too, even though the spec suggests putting
- them in the same layer.
-
- Most transients are in the same layer as their mainwindow,
- see Workspace::constrainedStackingOrder(), they may also be in higher layers, but
- they should never be below their mainwindow.
-
- When some client attribute changes (above/below flag, transiency...),
- Workspace::updateClientLayer() should be called in order to make
- sure it's moved to the appropriate layer ClientList if needed.
-
- Currently the things that affect client in which layer a client
- belongs: KeepAbove/Keep Below flags, window type, fullscreen
- state and whether the client is active, mainclient (transiency).
-
- Make sure updateStackingOrder() is called in order to make
- Workspace::stackingOrder() up to date and propagated to the world.
- Using Workspace::blockStackingUpdates() (or the StackingUpdatesBlocker
- helper class) it's possible to temporarily disable updates
- and the stacking order will be updated once after it's allowed again.
-
-*/
-
-#include <assert.h>
-
-#include <kdebug.h>
-
-#include "utils.h"
-#include "client.h"
-#include "workspace.h"
-#include "tabbox.h"
-#include "group.h"
-#include "rules.h"
-
-namespace KWinInternal
-{
-
-//*******************************
-// Workspace
-//*******************************
-
-void Workspace::updateClientLayer( Client* c )
- {
- if( c == NULL )
- return;
- if( c->layer() == c->belongsToLayer())
- return;
- StackingUpdatesBlocker blocker( this );
- c->invalidateLayer(); // tqinvalidate, will be updated when doing restacking
- for( ClientList::ConstIterator it = c->transients().begin();
- it != c->transients().end();
- ++it )
- updateClientLayer( *it );
- }
-
-void Workspace::updateStackingOrder( bool propagate_new_clients )
- {
- if( block_stacking_updates > 0 )
- {
- blocked_propagating_new_clients = blocked_propagating_new_clients || propagate_new_clients;
- return;
- }
- ClientList new_stacking_order = constrainedStackingOrder();
- bool changed = ( new_stacking_order != stacking_order );
- stacking_order = new_stacking_order;
-#if 0
- kdDebug() << "stacking:" << changed << endl;
- if( changed || propagate_new_clients )
- {
- for( ClientList::ConstIterator it = stacking_order.begin();
- it != stacking_order.end();
- ++it )
- kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
- }
-#endif
- if( changed || propagate_new_clients )
- {
- propagateClients( propagate_new_clients );
- if( active_client )
- active_client->updateMouseGrab();
- }
- }
-
-/*!
- Propagates the managed clients to the world.
- Called ONLY from updateStackingOrder().
- */
-void Workspace::propagateClients( bool propagate_new_clients )
- {
- Window *cl; // MW we should not assume WId and Window to be compatible
- // when passig pointers around.
-
- // restack the windows according to the stacking order
-#if 0
- Window* new_stack = new Window[ stacking_order.count() + 2 ];
- int pos = 0;
-#endif
- NET::WindowType t;
- Window shadow;
- Window *dock_shadow_stack, *window_stack;
- int i, numDocks, pos, topmenu_space_pos;
-
- dock_shadow_stack = new Window[ stacking_order.count() * 2 ];
- window_stack = new Window[ stacking_order.count() * 2 + 2 ];
- i = 0;
- pos = 0;
- topmenu_space_pos = 1; // not 0, that's supportWindow !!!
-
- // Stack all windows under the support window. The support window is
- // not used for anything (besides the NETWM property), and it's not shown,
- // but it was lowered after twin startup. Stacking all clients below
- // it ensures that no client will be ever shown above override-redirect
- // windows (e.g. popups).
-#if 0
- new_stack[ pos++ ] = supportWindow->winId();
- int topmenu_space_pos = 1; // not 0, that's supportWindow !!!
-#endif
- window_stack[pos++] = supportWindow->winId();
- for( ClientList::ConstIterator it = stacking_order.fromLast();
- it != stacking_order.end();
- --it )
- {
-#if 0
- new_stack[ pos++ ] = (*it)->frameId();
- if( (*it)->belongsToLayer() >= DockLayer )
- topmenu_space_pos = pos;
-#endif
- t = (*it)->windowType();
- switch (t)
- {
- case NET::Dock:
- window_stack[pos++] = (*it)->frameId();
- if ((shadow = (*it)->shadowId()) != None)
- dock_shadow_stack[i++] = shadow;
- break;
- case NET::Desktop:
- numDocks = i;
- for (i = 0; i < numDocks; i++)
- // Shadows for dock windows go just above the desktop
- window_stack[pos++] = dock_shadow_stack[i];
- window_stack[pos++] = (*it)->frameId();
- break;
- case NET::TopMenu:
- topmenu_space_pos = pos;
- // fall through
- default:
- window_stack[pos++] = (*it)->frameId();
- if ((shadow = (*it)->shadowId()) != None)
- // If the current window also has a shadow, place it
- // immediately under the current window
- window_stack[pos++] = shadow;
- }
- }
- if( topmenu_space != NULL )
- { // make sure the topmenu space is below all topmenus, fullscreens, etc.
- for( int i = pos;
- i > topmenu_space_pos;
- --i )
-#if 0
- new_stack[ i ] = new_stack[ i - 1 ];
- new_stack[ topmenu_space_pos ] = topmenu_space->winId();
-#endif
- window_stack[ i ] = window_stack[ i - 1 ];
- window_stack[ topmenu_space_pos ] = topmenu_space->winId();
- ++pos;
- }
-#if 0
- // TODO isn't it too inefficient to restart always all clients?
- // TODO don't restack not visible windows?
- assert( new_stack[ 0 ] = supportWindow->winId());
-#endif
-#if 0
- XRestackWindows(qt_xdisplay(), new_stack, pos);
- delete [] new_stack;
-#endif
- XRestackWindows(qt_xdisplay(), window_stack, pos);
- delete [] dock_shadow_stack;
- delete [] window_stack;
-
- if ( propagate_new_clients )
- {
- cl = new Window[ desktops.count() + clients.count()];
- pos = 0;
- // TODO this is still not completely in the map order
- for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it )
- cl[pos++] = (*it)->window();
- for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it )
- cl[pos++] = (*it)->window();
- rootInfo->setClientList( cl, pos );
- delete [] cl;
- }
-
- cl = new Window[ stacking_order.count()];
- pos = 0;
- for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
- cl[pos++] = (*it)->window();
- rootInfo->setClientListStacking( cl, pos );
- delete [] cl;
- }
-
-
-/*!
- Returns topmost visible client. Windows on the dock, the desktop
- or of any other special kind are excluded. Also if the window
- doesn't accept focus it's excluded.
- */
-// TODO misleading name for this method
-Client* Workspace::topClientOnDesktop( int desktop, bool unconstrained, bool only_normal ) const
- {
-// TODO Q_ASSERT( block_stacking_updates == 0 );
- ClientList::ConstIterator begin, end;
- if( !unconstrained )
- {
- begin = stacking_order.fromLast();
- end = stacking_order.end();
- }
- else
- {
- begin = unconstrained_stacking_order.fromLast();
- end = unconstrained_stacking_order.end();
- }
- for( ClientList::ConstIterator it = begin;
- it != end;
- --it )
- {
- if( (*it)->isOnDesktop( desktop ) && (*it)->isShown( false ))
- {
- if( !only_normal )
- return *it;
- if( (*it)->wantsTabFocus() && !(*it)->isSpecialWindow())
- return *it;
- }
- }
- return 0;
- }
-
-Client* Workspace::findDesktop( bool topmost, int desktop ) const
- {
-// TODO Q_ASSERT( block_stacking_updates == 0 );
- if( topmost )
- {
- for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
- {
- if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
- && (*it)->isShown( true ))
- return *it;
- }
- }
- else // bottom-most
- {
- for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
- {
- if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
- && (*it)->isShown( true ))
- return *it;
- }
- }
- return NULL;
- }
-
-void Workspace::raiseOrLowerClient( Client *c)
- {
- if (!c) return;
- Client* topmost = NULL;
-// TODO Q_ASSERT( block_stacking_updates == 0 );
- if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
- most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
- topmost = most_recently_raised;
- else
- topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
-
- if( c == topmost)
- lowerClient(c);
- else
- raiseClient(c);
- }
-
-
-void Workspace::lowerClient( Client* c )
- {
- if ( !c )
- return;
- if( c->isTopMenu())
- return;
-
- c->cancelAutoRaise();
-
- StackingUpdatesBlocker blocker( this );
-
- unconstrained_stacking_order.remove( c );
- unconstrained_stacking_order.prepend( c );
- if( c->isTransient())
- {
- // lower also mainclients, in their reversed stacking order
- ClientList mainclients = ensureStackingOrder( c->mainClients());
- for( ClientList::ConstIterator it = mainclients.fromLast();
- it != mainclients.end();
- ++it )
- lowerClient( *it );
- }
-
- if ( c == most_recently_raised )
- most_recently_raised = 0;
- }
-
-void Workspace::lowerClientWithinApplication( Client* c )
- {
- if ( !c )
- return;
- if( c->isTopMenu())
- return;
-
- c->cancelAutoRaise();
-
- StackingUpdatesBlocker blocker( this );
-
- unconstrained_stacking_order.remove( c );
- bool lowered = false;
- // first try to put it below the bottom-most window of the application
- for( ClientList::Iterator it = unconstrained_stacking_order.begin();
- it != unconstrained_stacking_order.end();
- ++it )
- if( Client::belongToSameApplication( *it, c ))
- {
- unconstrained_stacking_order.insert( it, c );
- lowered = true;
- break;
- }
- if( !lowered )
- unconstrained_stacking_order.prepend( c );
- // ignore mainwindows
- }
-
-void Workspace::raiseClient( Client* c )
- {
- if ( !c )
- return;
- if( c->isTopMenu())
- return;
-
- c->cancelAutoRaise();
-
- StackingUpdatesBlocker blocker( this );
-
- if( c->isTransient())
- {
- ClientList mainclients = ensureStackingOrder( c->mainClients());
- for( ClientList::ConstIterator it = mainclients.begin();
- it != mainclients.end();
- ++it )
- raiseClient( *it );
- }
-
- unconstrained_stacking_order.remove( c );
- unconstrained_stacking_order.append( c );
- if (options->shadowEnabled(c->isActive()))
- {
- c->removeShadow();
- c->drawDelayedShadow();
- }
-
- if( !c->isSpecialWindow())
- {
- most_recently_raised = c;
- pending_take_activity = NULL;
- }
- }
-
-void Workspace::raiseClientWithinApplication( Client* c )
- {
- if ( !c )
- return;
- if( c->isTopMenu())
- return;
-
- c->cancelAutoRaise();
-
- StackingUpdatesBlocker blocker( this );
- // ignore mainwindows
-
- // first try to put it above the top-most window of the application
- for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
- it != unconstrained_stacking_order.end();
- --it )
- {
- if( *it == c ) // don't lower it just because it asked to be raised
- return;
- if( Client::belongToSameApplication( *it, c ))
- {
- unconstrained_stacking_order.remove( c );
- ++it; // insert after the found one
- unconstrained_stacking_order.insert( it, c );
- return;
- }
- }
- }
-
-void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp )
- {
- if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
- raiseClient( c );
- else
- {
- raiseClientWithinApplication( c );
- c->demandAttention();
- }
- }
-
-void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time /*timestamp*/ )
- {
- // If the client has support for all this focus stealing prevention stuff,
- // do only lowering within the application, as that's the more logical
- // variant of lowering when application requests it.
- // No demanding of attention here of course.
- if( src == NET::FromTool || !c->hasUserTimeSupport())
- lowerClient( c );
- else
- lowerClientWithinApplication( c );
- }
-
-void Workspace::restackClientUnderActive( Client* c )
- {
- if( c->isTopMenu())
- return;
- if( !active_client || active_client == c )
- {
- raiseClient( c );
- return;
- }
-
- assert( unconstrained_stacking_order.contains( active_client ));
- if( Client::belongToSameApplication( active_client, c ))
- { // put it below the active window if it's the same app
- unconstrained_stacking_order.remove( c );
- unconstrained_stacking_order.insert( unconstrained_stacking_order.find( active_client ), c );
- }
- else
- { // put in the stacking order below _all_ windows belonging to the active application
- for( ClientList::Iterator it = unconstrained_stacking_order.begin();
- it != unconstrained_stacking_order.end();
- ++it )
- { // TODO ignore topmenus?
- if( Client::belongToSameApplication( active_client, *it ))
- {
- if( *it != c )
- {
- unconstrained_stacking_order.remove( c );
- unconstrained_stacking_order.insert( it, c );
- }
- break;
- }
- }
- }
- assert( unconstrained_stacking_order.contains( c ));
- for( int desktop = 1;
- desktop <= numberOfDesktops();
- ++desktop )
- { // do for every virtual desktop to handle the case of onalldesktop windows
- if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client ))
- {
- if( Client::belongToSameApplication( active_client, c ))
- { // put it after the active window if it's the same app
- focus_chain[ desktop ].remove( c );
- focus_chain[ desktop ].insert( focus_chain[ desktop ].find( active_client ), c );
- }
- else
- { // put it in focus_chain[currentDesktop()] after all windows belonging to the active applicationa
- focus_chain[ desktop ].remove( c );
- for( ClientList::Iterator it = focus_chain[ desktop ].fromLast();
- it != focus_chain[ desktop ].end();
- --it )
- {
- if( Client::belongToSameApplication( active_client, *it ))
- {
- focus_chain[ desktop ].insert( it, c );
- break;
- }
- }
- }
- }
- }
- // the same for global_focus_chain
- if( c->wantsTabFocus() && global_focus_chain.contains( active_client ))
- {
- if( Client::belongToSameApplication( active_client, c ))
- {
- global_focus_chain.remove( c );
- global_focus_chain.insert( global_focus_chain.find( active_client ), c );
- }
- else
- {
- global_focus_chain.remove( c );
- for( ClientList::Iterator it = global_focus_chain.fromLast();
- it != global_focus_chain.end();
- --it )
- {
- if( Client::belongToSameApplication( active_client, *it ))
- {
- global_focus_chain.insert( it, c );
- break;
- }
- }
- }
- }
- updateStackingOrder();
- }
-
-void Workspace::circulateDesktopApplications()
- {
- if ( desktops.count() > 1 )
- {
- bool change_active = activeClient()->isDesktop();
- raiseClient( findDesktop( false, currentDesktop()));
- if( change_active ) // if the previously topmost Desktop was active, activate this new one
- activateClient( findDesktop( true, currentDesktop()));
- }
- // if there's no active client, make desktop the active one
- if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
- activateClient( findDesktop( true, currentDesktop()));
- }
-
-
-/*!
- Returns a stacking order based upon \a list that fulfills certain contained.
- */
-ClientList Workspace::constrainedStackingOrder()
- {
- ClientList layer[ NumLayers ];
-
-#if 0
- kdDebug() << "stacking1:" << endl;
-#endif
- // build the order from layers
- TQMap< Group*, Layer > minimum_layer;
- for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
- it != unconstrained_stacking_order.end();
- ++it )
- {
- Layer l = (*it)->layer();
- // If a window is raised above some other window in the same window group
- // which is in the ActiveLayer (i.e. it's fulscreened), make sure it stays
- // above that window (see #95731).
- if( minimum_layer.contains( (*it)->group())
- && minimum_layer[ (*it)->group() ] == ActiveLayer
- && ( l == NormalLayer || l == AboveLayer ))
- {
- l = minimum_layer[ (*it)->group() ];
- }
- minimum_layer[ (*it)->group() ] = l;
- layer[ l ].append( *it );
- }
- ClientList stacking;
- for( Layer lay = FirstLayer;
- lay < NumLayers;
- ++lay )
- stacking += layer[ lay ];
-#if 0
- kdDebug() << "stacking2:" << endl;
- for( ClientList::ConstIterator it = stacking.begin();
- it != stacking.end();
- ++it )
- kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
-#endif
- // now keep transients above their mainwindows
- // TODO this could(?) use some optimization
- for( ClientList::Iterator it = stacking.fromLast();
- it != stacking.end();
- )
- {
- if( !(*it)->isTransient())
- {
- --it;
- continue;
- }
- ClientList::Iterator it2 = stacking.end();
- if( (*it)->groupTransient())
- {
- if( (*it)->group()->members().count() > 0 )
- { // find topmost client this one is transient for
- for( it2 = stacking.fromLast();
- it2 != stacking.end();
- --it2 )
- {
- if( *it2 == *it )
- {
- it2 = stacking.end(); // don't reorder
- break;
- }
- if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
- break;
- }
- } // else it2 remains pointing at stacking.end()
- }
- else
- {
- for( it2 = stacking.fromLast();
- it2 != stacking.end();
- --it2 )
- {
- if( *it2 == *it )
- {
- it2 = stacking.end(); // don't reorder
- break;
- }
- if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
- break;
- }
- }
-// kdDebug() << "STACK:" << (*it) << ":" << ( it2 == stacking.end() ? ((Client*)0) : (*it2)) << endl;
- if( it2 == stacking.end())
- {
- --it;
- continue;
- }
- Client* current = *it;
- ClientList::Iterator remove_it = it;
- --it;
- stacking.remove( remove_it );
- if( !current->transients().isEmpty()) // this one now can be possibly above its transients,
- it = it2; // so go again higher in the stack order and possibly move those transients again
- ++it2; // insert after the mainwindow, it's ok if it2 is now stacking.end()
- stacking.insert( it2, current );
- }
-#if 0
- kdDebug() << "stacking3:" << endl;
- for( ClientList::ConstIterator it = stacking.begin();
- it != stacking.end();
- ++it )
- kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
- kdDebug() << "\n\n" << endl;
-#endif
- return stacking;
- }
-
-void Workspace::blockStackingUpdates( bool block )
- {
- if( block )
- {
- if( block_stacking_updates == 0 )
- blocked_propagating_new_clients = false;
- ++block_stacking_updates;
- }
- else // !block
- if( --block_stacking_updates == 0 )
- updateStackingOrder( blocked_propagating_new_clients );
- }
-
-// Ensure list is in stacking order
-ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
- {
-// TODO Q_ASSERT( block_stacking_updates == 0 );
- if( list.count() < 2 )
- return list;
- // TODO is this worth optimizing?
- ClientList result = list;
- for( ClientList::ConstIterator it = stacking_order.begin();
- it != stacking_order.end();
- ++it )
- if( result.remove( *it ) != 0 )
- result.append( *it );
- return result;
- }
-
-// check whether a transient should be actually kept above its mainwindow
-// there may be some special cases where this rule shouldn't be enfored
-bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
- {
- // When topmenu's mainwindow becomes active, topmenu is raised and shown.
- // They also belong to the Dock layer. This makes them to be very high.
- // Therefore don't keep group transients above them, otherwise this would move
- // group transients way too high.
- if( mainwindow->isTopMenu() && transient->groupTransient())
- return false;
- // #93832 - don't keep splashscreens above dialogs
- if( transient->isSplash() && mainwindow->isDialog())
- return false;
- // This is rather a hack for #76026. Don't keep non-modal dialogs above
- // the mainwindow, but only if they're group transient (since only such dialogs
- // have taskbar entry in Kicker). A proper way of doing this (both twin and kicker)
- // needs to be found.
- if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
- return false;
- // #63223 - don't keep transients above docks, because the dock is kept high,
- // and e.g. dialogs for them would be too high too
- if( mainwindow->isDock())
- return false;
- return true;
- }
-
-//*******************************
-// Client
-//*******************************
-
-void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event )
- {
- switch ( detail )
- {
- case Above:
- case TopIf:
- workspace()->raiseClientRequest( this, src, timestamp );
- break;
- case Below:
- case BottomIf:
- workspace()->lowerClientRequest( this, src, timestamp );
- break;
- case Opposite:
- default:
- break;
- }
- if( send_event )
- sendSyntheticConfigureNotify();
- }
-
-void Client::setKeepAbove( bool b )
- {
- b = rules()->checkKeepAbove( b );
- if( b && !rules()->checkKeepBelow( false ))
- setKeepBelow( false );
- if ( b == keepAbove())
- { // force hint change if different
- if( bool( info->state() & NET::KeepAbove ) != keepAbove())
- info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
- return;
- }
- keep_above = b;
- info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
- if( decoration != NULL )
- decoration->emitKeepAboveChanged( keepAbove());
- workspace()->updateClientLayer( this );
- updateWindowRules();
- }
-
-void Client::setKeepBelow( bool b )
- {
- b = rules()->checkKeepBelow( b );
- if( b && !rules()->checkKeepAbove( false ))
- setKeepAbove( false );
- if ( b == keepBelow())
- { // force hint change if different
- if( bool( info->state() & NET::KeepBelow ) != keepBelow())
- info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
- return;
- }
- keep_below = b;
- info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
- if( decoration != NULL )
- decoration->emitKeepBelowChanged( keepBelow());
- workspace()->updateClientLayer( this );
- updateWindowRules();
- }
-
-Layer Client::layer() const
- {
- if( in_layer == UnknownLayer )
- const_cast< Client* >( this )->in_layer = belongsToLayer();
- return in_layer;
- }
-
-Layer Client::belongsToLayer() const
- {
- if( isDesktop())
- return DesktopLayer;
- if( isSplash()) // no damn annoying splashscreens
- return NormalLayer; // getting in the way of everything else
- if( isDock() && keepBelow())
- // slight hack for the 'allow window to cover panel' Kicker setting
- // don't move keepbelow docks below normal window, but only to the same
- // layer, so that both may be raised to cover the other
- return NormalLayer;
- if( keepBelow())
- return BelowLayer;
- if( isDock() && !keepBelow())
- return DockLayer;
- if( isTopMenu())
- return DockLayer;
- // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
- // i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
- const Client* ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker
- const Client* top = workspace()->topClientOnDesktop( desktop(), true, false );
- if( isFullScreen() && ac != NULL && top != NULL
- && ( ac == this || this->group() == ac->group())
- && ( top == this || this->group() == top->group()))
- return ActiveLayer;
- if( keepAbove())
- return AboveLayer;
- return NormalLayer;
- }
-
-} // namespace