kwin Library API Documentation

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