layers.cpp

00001 /*****************************************************************
00002  KWin - the KDE window manager
00003  This file is part of the KDE project.
00004 
00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
00007 
00008 You can Freely distribute this program under the GNU General Public
00009 License. See the file "COPYING" for the exact licensing terms.
00010 ******************************************************************/
00011 
00012 // SELI zmenit doc
00013 
00014 /*
00015 
00016  This file contains things relevant to stacking order and layers.
00017 
00018  Design:
00019 
00020  Normal unconstrained stacking order, as requested by the user (by clicking
00021  on windows to raise them, etc.), is in Workspace::unconstrained_stacking_order.
00022  That list shouldn't be used at all, except for building
00023  Workspace::stacking_order. The building is done
00024  in Workspace::constrainedStackingOrder(). Only Workspace::stackingOrder() should
00025  be used to get the stacking order, because it also checks the stacking order
00026  is up to date.
00027  All clients are also stored in Workspace::clients (except for isDesktop() clients,
00028  as those are very special, and are stored in Workspace::desktops), in the order
00029  the clients were created.
00030 
00031  Every window has one layer assigned in which it is. There are 6 layers,
00032  from bottom : DesktopLayer, BelowLayer, NormalLayer, DockLayer, AboveLayer
00033  and ActiveLayer (see also NETWM sect.7.10.). The layer a window is in depends
00034  on the window type, and on other things like whether the window is active.
00035 
00036  NET::Splash clients belong to the Normal layer. NET::TopMenu clients
00037  belong to Dock layer. Clients that are both NET::Dock and NET::KeepBelow
00038  are in the Normal layer in order to keep the 'allow window to cover
00039  the panel' Kicker setting to work as intended (this may look like a slight
00040  spec violation, but a) I have no better idea, b) the spec allows adjusting
00041  the stacking order if the WM thinks it's a good idea . We put all
00042  NET::KeepAbove above all Docks too, even though the spec suggests putting
00043  them in the same layer.
00044 
00045  Most transients are in the same layer as their mainwindow,
00046  see Workspace::constrainedStackingOrder(), they may also be in higher layers, but
00047  they should never be below their mainwindow.
00048 
00049  When some client attribute changes (above/below flag, transiency...),
00050  Workspace::updateClientLayer() should be called in order to make
00051  sure it's moved to the appropriate layer ClientList if needed.
00052 
00053  Currently the things that affect client in which layer a client
00054  belongs: KeepAbove/Keep Below flags, window type, fullscreen
00055  state and whether the client is active, mainclient (transiency).
00056 
00057  Make sure updateStackingOrder() is called in order to make
00058  Workspace::stackingOrder() up to date and propagated to the world.
00059  Using Workspace::blockStackingUpdates() (or the StackingUpdatesBlocker
00060  helper class) it's possible to temporarily disable updates
00061  and the stacking order will be updated once after it's allowed again.
00062 
00063 */
00064 
00065 #include <assert.h>
00066 
00067 #include <kdebug.h>
00068 
00069 #include "utils.h"
00070 #include "client.h"
00071 #include "workspace.h"
00072 #include "tabbox.h"
00073 #include "group.h"
00074 #include "rules.h"
00075 
00076 extern Time qt_x_time;
00077 
00078 namespace KWinInternal
00079 {
00080 
00081 //*******************************
00082 // Workspace
00083 //*******************************
00084 
00085 void Workspace::updateClientLayer( Client* c )
00086     {
00087     if( c == NULL )
00088         return;
00089     if( c->layer() == c->belongsToLayer())
00090         return;
00091     StackingUpdatesBlocker blocker( this );
00092     c->invalidateLayer(); // invalidate, will be updated when doing restacking
00093     for( ClientList::ConstIterator it = c->transients().begin();
00094          it != c->transients().end();
00095          ++it )
00096         updateClientLayer( *it );
00097     }
00098 
00099 void Workspace::updateStackingOrder( bool propagate_new_clients )
00100     {
00101     if( block_stacking_updates > 0 )
00102         {
00103         blocked_propagating_new_clients |= propagate_new_clients;
00104         return;
00105         }
00106     ClientList new_stacking_order = constrainedStackingOrder();
00107     bool changed = ( new_stacking_order != stacking_order );
00108     stacking_order = new_stacking_order;
00109 #if 0
00110     kdDebug() << "stacking:" << changed << endl;
00111     if( changed || propagate_new_clients )
00112         {
00113         for( ClientList::ConstIterator it = stacking_order.begin();
00114              it != stacking_order.end();
00115              ++it )
00116             kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00117         }
00118 #endif
00119     if( changed || propagate_new_clients )
00120         propagateClients( propagate_new_clients );
00121     }
00122 
00127 void Workspace::propagateClients( bool propagate_new_clients )
00128     {
00129     Window *cl; // MW we should not assume WId and Window to be compatible
00130                                 // when passig pointers around.
00131 
00132     // restack the windows according to the stacking order
00133     Window* new_stack = new Window[ stacking_order.count() + 2 ];
00134     int pos = 0;
00135     // Stack all windows under the support window. The support window is
00136     // not used for anything (besides the NETWM property), and it's not shown,
00137     // but it was lowered after kwin startup. Stacking all clients below
00138     // it ensures that no client will be ever shown above override-redirect
00139     // windows (e.g. popups).
00140     new_stack[ pos++ ] = supportWindow->winId();
00141     int topmenu_space_pos = 1; // not 0, that's supportWindow !!!
00142     for( ClientList::ConstIterator it = stacking_order.fromLast();
00143          it != stacking_order.end();
00144          --it )
00145         {
00146         new_stack[ pos++ ] = (*it)->frameId();
00147         if( (*it)->belongsToLayer() >= DockLayer )
00148             topmenu_space_pos = pos;
00149         }
00150     if( topmenu_space != NULL )
00151         { // make sure the topmenu space is below all topmenus, fullscreens, etc.
00152         for( int i = pos;
00153              i > topmenu_space_pos;
00154              --i )
00155             new_stack[ i ] = new_stack[ i - 1 ];
00156         new_stack[ topmenu_space_pos ] = topmenu_space->winId();
00157         ++pos;
00158         }
00159     // TODO isn't it too inefficient to restart always all clients?
00160     // TODO don't restack not visible windows?
00161     assert( new_stack[ 0 ] = supportWindow->winId());
00162     XRestackWindows(qt_xdisplay(), new_stack, pos);
00163     delete [] new_stack;
00164 
00165     if ( propagate_new_clients )
00166         {
00167         cl = new Window[ desktops.count() + clients.count()];
00168         pos = 0;
00169     // TODO this is still not completely in the map order
00170         for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it )
00171             cl[pos++] =  (*it)->window();
00172         for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it )
00173             cl[pos++] =  (*it)->window();
00174         rootInfo->setClientList( cl, pos );
00175         delete [] cl;
00176         }
00177 
00178     cl = new Window[ stacking_order.count()];
00179     pos = 0;
00180     for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
00181         cl[pos++] =  (*it)->window();
00182     rootInfo->setClientListStacking( cl, pos );
00183     delete [] cl;
00184     }
00185 
00186 
00192 // TODO misleading name for this method
00193 Client* Workspace::topClientOnDesktop( int desktop, bool unconstrained ) const
00194     {
00195 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00196     ClientList::ConstIterator begin, end;
00197     if( !unconstrained )
00198         {
00199         begin = stacking_order.fromLast();
00200         end = stacking_order.end();
00201         }
00202     else
00203         {
00204         begin = unconstrained_stacking_order.fromLast();
00205         end = unconstrained_stacking_order.end();
00206         }
00207     for( ClientList::ConstIterator it = begin;
00208         it != end;
00209         --it )
00210         {
00211         if ( (*it)->isOnDesktop( desktop ) && !(*it)->isSpecialWindow()
00212             && (*it)->isShown( false ) && (*it)->wantsTabFocus())
00213             return *it;
00214         }
00215     return 0;
00216     }
00217 
00218 Client* Workspace::findDesktop( bool topmost, int desktop ) const
00219     {
00220 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00221     if( topmost )
00222         {
00223         for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
00224             {
00225             if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
00226                 && (*it)->isShown( true ))
00227                 return *it;
00228             }
00229         }
00230     else // bottom-most
00231         {
00232         for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
00233             {
00234             if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
00235                 && (*it)->isShown( true ))
00236                 return *it;
00237             }
00238         }
00239     return NULL;
00240     }
00241 
00242 void Workspace::raiseOrLowerClient( Client *c)
00243     {
00244     if (!c) return;
00245     Client* topmost = NULL;
00246 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00247     if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
00248          most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
00249         topmost = most_recently_raised;
00250     else
00251         topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
00252 
00253     if( c == topmost)
00254         lowerClient(c);
00255     else
00256         raiseClient(c);
00257     }
00258 
00259 
00260 void Workspace::lowerClient( Client* c )
00261     {
00262     if ( !c )
00263         return;
00264     if( c->isTopMenu())
00265         return;
00266 
00267     c->cancelAutoRaise();
00268 
00269     StackingUpdatesBlocker blocker( this );
00270 
00271     unconstrained_stacking_order.remove( c );
00272     unconstrained_stacking_order.prepend( c );
00273     if( c->isTransient())
00274         {
00275         // lower also mainclients, in their reversed stacking order
00276         ClientList mainclients = ensureStackingOrder( c->mainClients());
00277         for( ClientList::ConstIterator it = mainclients.fromLast();
00278              it != mainclients.end();
00279              ++it )
00280             lowerClient( *it );
00281         }
00282 
00283     if ( c == most_recently_raised )
00284         most_recently_raised = 0;
00285     }
00286 
00287 void Workspace::lowerClientWithinApplication( Client* c )
00288     {
00289     if ( !c )
00290         return;
00291     if( c->isTopMenu())
00292         return;
00293 
00294     c->cancelAutoRaise();
00295 
00296     StackingUpdatesBlocker blocker( this );
00297 
00298     unconstrained_stacking_order.remove( c );
00299     bool lowered = false;
00300     // first try to put it below the bottom-most window of the application
00301     for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00302          it != unconstrained_stacking_order.end();
00303          ++it )
00304         if( Client::belongToSameApplication( *it, c ))
00305             {
00306             unconstrained_stacking_order.insert( it, c );
00307             lowered = true;
00308             break;
00309             }
00310     if( !lowered )
00311         unconstrained_stacking_order.prepend( c );
00312     // ignore mainwindows
00313     }
00314 
00315 void Workspace::raiseClient( Client* c )
00316     {
00317     if ( !c )
00318         return;
00319     if( c->isTopMenu())
00320         return;
00321 
00322     c->cancelAutoRaise();
00323 
00324     StackingUpdatesBlocker blocker( this );
00325 
00326     if( c->isTransient())
00327         {
00328         ClientList mainclients = ensureStackingOrder( c->mainClients());
00329         for( ClientList::ConstIterator it = mainclients.begin();
00330              it != mainclients.end();
00331              ++it )
00332             raiseClient( *it );
00333         }
00334 
00335     unconstrained_stacking_order.remove( c );
00336     unconstrained_stacking_order.append( c );
00337 
00338     if( !c->isSpecialWindow())
00339         {
00340         most_recently_raised = c;
00341         pending_take_activity = NULL;
00342         }
00343     }
00344 
00345 void Workspace::raiseClientWithinApplication( Client* c )
00346     {
00347     if ( !c )
00348         return;
00349     if( c->isTopMenu())
00350         return;
00351 
00352     c->cancelAutoRaise();
00353 
00354     StackingUpdatesBlocker blocker( this );
00355     // ignore mainwindows
00356     
00357     // first try to put it above the top-most window of the application
00358     for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
00359          it != unconstrained_stacking_order.end();
00360          --it )
00361         {
00362         if( *it == c ) // don't lower it just because it asked to be raised
00363             return;
00364         if( Client::belongToSameApplication( *it, c ))
00365             {
00366             unconstrained_stacking_order.remove( c );
00367             ++it; // insert after the found one
00368             unconstrained_stacking_order.insert( it, c );
00369             return;
00370             }
00371         }
00372     }
00373 
00374 void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp )
00375     {
00376     if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
00377         raiseClient( c );
00378     else
00379         {
00380         raiseClientWithinApplication( c );
00381         c->demandAttention();
00382         }
00383     }
00384 
00385 void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time /*timestamp*/ )
00386     {
00387     // If the client has support for all this focus stealing prevention stuff,
00388     // do only lowering within the application, as that's the more logical
00389     // variant of lowering when application requests it.
00390     // No demanding of attention here of course.
00391     if( src == NET::FromTool || !c->hasUserTimeSupport())
00392         lowerClient( c );
00393     else
00394         lowerClientWithinApplication( c );
00395     }
00396 
00397 void Workspace::restackClientUnderActive( Client* c )
00398     {
00399     if( c->isTopMenu())
00400         return;
00401     if( !active_client || active_client == c )
00402         {
00403         raiseClient( c );
00404         return;
00405         }
00406 
00407     // put in the stacking order below _all_ windows belonging to the active application
00408     assert( unconstrained_stacking_order.contains( active_client ));
00409     for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00410          it != unconstrained_stacking_order.end();
00411          ++it )
00412         { // TODO ignore topmenus?
00413         if( Client::belongToSameApplication( active_client, *it ))
00414             {
00415             if( *it != c )
00416                 {
00417                 unconstrained_stacking_order.remove( c );
00418                 unconstrained_stacking_order.insert( it, c );
00419                 }
00420             break;
00421             }
00422         }
00423     assert( unconstrained_stacking_order.contains( c ));
00424     if( c->wantsTabFocus() && focus_chain.contains( active_client ))
00425         {
00426         // also put in focus_chain after all windows belonging to the active application
00427         focus_chain.remove( c );
00428         for( ClientList::Iterator it = focus_chain.fromLast();
00429              it != focus_chain.end();
00430              --it )
00431             {
00432             if( Client::belongToSameApplication( active_client, *it ))
00433                 {
00434                 focus_chain.insert( it, c );
00435                 break;
00436                 }
00437             }
00438         }
00439     updateStackingOrder();
00440     }
00441 
00442 void Workspace::circulateDesktopApplications()
00443     {
00444     if ( desktops.count() > 1 )
00445         {
00446         bool change_active = activeClient()->isDesktop();
00447         raiseClient( findDesktop( false, currentDesktop()));
00448         if( change_active ) // if the previously topmost Desktop was active, activate this new one
00449             activateClient( findDesktop( true, currentDesktop()));
00450         }
00451     // if there's no active client, make desktop the active one
00452     if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00453         activateClient( findDesktop( true, currentDesktop()));
00454     }
00455 
00456 
00460 ClientList Workspace::constrainedStackingOrder()
00461     {
00462     ClientList layer[ NumLayers ];
00463 
00464 #if 0
00465     kdDebug() << "stacking1:" << endl;
00466 #endif
00467     // build the order from layers
00468     QMap< Group*, Layer > minimum_layer;
00469     for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00470          it != unconstrained_stacking_order.end();
00471          ++it )
00472         {
00473         Layer l = (*it)->layer();
00474         // If a window is raised above some other window in the same window group
00475         // which is in the ActiveLayer (i.e. it's fulscreened), make sure it stays
00476         // above that window (see #95731).
00477         if( minimum_layer.contains( (*it)->group())
00478             && minimum_layer[ (*it)->group() ] == ActiveLayer
00479             && ( l == NormalLayer || l == AboveLayer ))
00480             {
00481             l = minimum_layer[ (*it)->group() ];
00482             }
00483         minimum_layer[ (*it)->group() ] = l;
00484         layer[ l ].append( *it );
00485         }
00486     ClientList stacking;    
00487     for( Layer lay = FirstLayer;
00488          lay < NumLayers;
00489          ++lay )    
00490         stacking += layer[ lay ];
00491 #if 0
00492     kdDebug() << "stacking2:" << endl;
00493     for( ClientList::ConstIterator it = stacking.begin();
00494          it != stacking.end();
00495          ++it )
00496         kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00497 #endif
00498     // now keep transients above their mainwindows
00499     // TODO this could(?) use some optimization
00500     for( ClientList::Iterator it = stacking.fromLast();
00501          it != stacking.end();
00502          )
00503         {
00504         if( !(*it)->isTransient())
00505             {
00506             --it;
00507             continue;
00508             }
00509         ClientList::Iterator it2 = stacking.end();
00510         if( (*it)->groupTransient())
00511             {
00512             if( (*it)->group()->members().count() > 0 )
00513                 { // find topmost client this one is transient for
00514                 for( it2 = stacking.fromLast();
00515                      it2 != stacking.end();
00516                      --it2 )
00517                     {
00518                     if( *it2 == *it )
00519                         {
00520                         it2 = stacking.end(); // don't reorder
00521                         break;
00522                         }
00523                     if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
00524                         break;
00525                     }
00526                 } // else it2 remains pointing at stacking.end()
00527             }
00528         else
00529             {
00530             for( it2 = stacking.fromLast();
00531                  it2 != stacking.end();
00532                  --it2 )
00533                 {
00534                 if( *it2 == *it )
00535                     {
00536                     it2 = stacking.end(); // don't reorder
00537                     break;
00538                     }
00539                 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00540                     break;
00541                 }
00542             }
00543 //        kdDebug() << "STACK:" << (*it) << ":" << ( it2 == stacking.end() ? ((Client*)0) : (*it2)) << endl;
00544         if( it2 == stacking.end())
00545             {
00546             --it;
00547             continue;
00548             }
00549         Client* current = *it;
00550         ClientList::Iterator remove_it = it;
00551         --it;
00552         stacking.remove( remove_it );
00553         if( !current->transients().isEmpty())  // this one now can be possibly above its transients,
00554             it = it2; // so go again higher in the stack order and possibly move those transients again
00555         ++it2; // insert after the mainwindow, it's ok if it2 is now stacking.end()
00556         stacking.insert( it2, current );
00557         }
00558 #if 0
00559     kdDebug() << "stacking3:" << endl;
00560     for( ClientList::ConstIterator it = stacking.begin();
00561          it != stacking.end();
00562          ++it )
00563         kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00564     kdDebug() << "\n\n" << endl;
00565 #endif
00566     return stacking;
00567     }
00568 
00569 void Workspace::blockStackingUpdates( bool block )
00570     {
00571     if( block )
00572         {
00573         if( block_stacking_updates == 0 )
00574             blocked_propagating_new_clients = false;
00575         ++block_stacking_updates;
00576         }
00577     else // !block
00578         if( --block_stacking_updates == 0 )
00579             updateStackingOrder( blocked_propagating_new_clients );
00580     }
00581 
00582 // Ensure list is in stacking order
00583 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00584     {
00585 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00586     if( list.count() < 2 )
00587         return list;
00588     // TODO is this worth optimizing?
00589     ClientList result = list;
00590     for( ClientList::ConstIterator it = stacking_order.begin();
00591          it != stacking_order.end();
00592          ++it )
00593         if( result.remove( *it ) != 0 )
00594             result.append( *it );
00595     return result;
00596     }
00597 
00598 // check whether a transient should be actually kept above its mainwindow
00599 // there may be some special cases where this rule shouldn't be enfored
00600 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00601     {
00602     // When topmenu's mainwindow becomes active, topmenu is raised and shown.
00603     // They also belong to the Dock layer. This makes them to be very high.
00604     // Therefore don't keep group transients above them, otherwise this would move
00605     // group transients way too high.
00606     if( mainwindow->isTopMenu() && transient->groupTransient())
00607         return false;
00608     // #93832 - don't keep splashscreens above dialogs
00609     if( transient->isSplash() && mainwindow->isDialog())
00610         return false;
00611     // This is rather a hack for #76026. Don't keep non-modal dialogs above
00612     // the mainwindow, but only if they're group transient (since only such dialogs
00613     // have taskbar entry in Kicker). A proper way of doing this (both kwin and kicker)
00614     // needs to be found.
00615     if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
00616         return false;
00617     // #63223 - don't keep transients above docks, because the dock is kept high,
00618     // and e.g. dialogs for them would be too high too
00619     if( mainwindow->isDock())
00620         return false;
00621     return true;
00622     }
00623 
00624 //*******************************
00625 // Client
00626 //*******************************
00627 
00628 void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event )
00629     {
00630     switch ( detail )
00631         {
00632         case Above:
00633         case TopIf:
00634             workspace()->raiseClientRequest( this, src, timestamp );
00635           break;
00636         case Below:
00637         case BottomIf:
00638             workspace()->lowerClientRequest( this, src, timestamp );
00639           break;
00640         case Opposite:
00641         default:
00642             break;
00643         }
00644     if( send_event )
00645         sendSyntheticConfigureNotify();
00646     }
00647     
00648 void Client::setKeepAbove( bool b )
00649     {
00650     b = rules()->checkKeepAbove( b );
00651     if( b && !rules()->checkKeepBelow( false ))
00652         setKeepBelow( false );
00653     if ( b == keepAbove())
00654         { // force hint change if different
00655         if( bool( info->state() & NET::KeepAbove ) != keepAbove())
00656             info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00657         return;
00658         }
00659     keep_above = b;
00660     info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00661     if( decoration != NULL )
00662         decoration->emitKeepAboveChanged( keepAbove());
00663     workspace()->updateClientLayer( this );
00664     updateWindowRules();
00665     }
00666 
00667 void Client::setKeepBelow( bool b )
00668     {
00669     b = rules()->checkKeepBelow( b );
00670     if( b && !rules()->checkKeepAbove( false ))
00671         setKeepAbove( false );
00672     if ( b == keepBelow())
00673         { // force hint change if different
00674         if( bool( info->state() & NET::KeepBelow ) != keepBelow())
00675             info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00676         return;
00677         }
00678     keep_below = b;
00679     info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00680     if( decoration != NULL )
00681         decoration->emitKeepBelowChanged( keepBelow());
00682     workspace()->updateClientLayer( this );
00683     updateWindowRules();
00684     }
00685 
00686 Layer Client::layer() const
00687     {
00688     if( in_layer == UnknownLayer )
00689         const_cast< Client* >( this )->in_layer = belongsToLayer();
00690     return in_layer;
00691     }
00692 
00693 Layer Client::belongsToLayer() const
00694     {
00695     if( isDesktop())
00696         return DesktopLayer;
00697     if( isSplash())         // no damn annoying splashscreens
00698         return NormalLayer; // getting in the way of everything else
00699     if( isDock() && keepBelow())
00700         // slight hack for the 'allow window to cover panel' Kicker setting
00701         // don't move keepbelow docks below normal window, but only to the same
00702         // layer, so that both may be raised to cover the other
00703         return NormalLayer;
00704     if( keepBelow())
00705         return BelowLayer;
00706     if( isDock() && !keepBelow())
00707         return DockLayer;
00708     if( isTopMenu())
00709         return DockLayer;
00710     // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
00711     // i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
00712     const Client* ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker
00713     const Client* top = workspace()->topClientOnDesktop( desktop(), true );
00714     if( isFullScreen() && ac != NULL && top != NULL
00715         && ( ac == this || this->group() == ac->group())
00716         && ( top == this || this->group() == top->group()))
00717         return ActiveLayer;
00718     if( keepAbove())
00719         return AboveLayer;
00720     return NormalLayer;
00721     }
00722 
00723 } // namespace
KDE Home | KDE Accessibility Home | Description of Access Keys