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     for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00480          it != unconstrained_stacking_order.end();
00481          ++it )
00482         {
00483 #if 0
00484         kdDebug() << (void*)(*it) << *it << endl;
00485 #endif
00486         layer[ (*it)->layer() ].append( *it );
00487         }
00488     ClientList stacking;    
00489     for( Layer lay = FirstLayer;
00490          lay < NumLayers;
00491          ++lay )    
00492         stacking += layer[ lay ];
00493 #if 0
00494     kdDebug() << "stacking2:" << endl;
00495     for( ClientList::ConstIterator it = stacking.begin();
00496          it != stacking.end();
00497          ++it )
00498         kdDebug() << (void*)(*it) << *it << endl;
00499 #endif
00500     // now keep transients above their mainwindows
00501     // TODO this could(?) use some optimization
00502     for( ClientList::Iterator it = stacking.fromLast();
00503          it != stacking.end();
00504          )
00505         {
00506         if( !(*it)->isTransient())
00507             {
00508             --it;
00509             continue;
00510             }
00511         ClientList::Iterator it2 = stacking.end();
00512         if( (*it)->groupTransient())
00513             {
00514             if( (*it)->group()->members().count() > 0 )
00515                 { // find topmost client this one is transient for
00516                 for( it2 = stacking.fromLast();
00517                      it2 != stacking.end();
00518                      --it2 )
00519                     {
00520                     if( *it2 == *it )
00521                         {
00522                         it2 = stacking.end(); // don't reorder
00523                         break;
00524                         }
00525                     if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
00526                         break;
00527                     }
00528                 } // else it2 remains pointing at stacking.end()
00529             }
00530         else
00531             {
00532             for( it2 = stacking.fromLast();
00533                  it2 != stacking.end();
00534                  --it2 )
00535                 {
00536                 if( *it2 == *it )
00537                     {
00538                     it2 = stacking.end(); // don't reorder
00539                     break;
00540                     }
00541                 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00542                     break;
00543                 }
00544             }
00545 //        kdDebug() << "STACK:" << (*it) << ":" << ( it2 == stacking.end() ? ((Client*)0) : (*it2)) << endl;
00546         if( it2 == stacking.end())
00547             {
00548             --it;
00549             continue;
00550             }
00551         Client* current = *it;
00552         ClientList::Iterator remove_it = it;
00553         --it;
00554         stacking.remove( remove_it );
00555         if( !current->transients().isEmpty())  // this one now can be possibly above its transients,
00556             it = it2; // so go again higher in the stack order and possibly move those transients again
00557         ++it2; // insert after the mainwindow, it's ok if it2 is now stacking.end()
00558         stacking.insert( it2, current );
00559         }
00560 #if 0
00561     kdDebug() << "stacking3:" << endl;
00562     for( ClientList::ConstIterator it = stacking.begin();
00563          it != stacking.end();
00564          ++it )
00565         kdDebug() << (void*)(*it) << *it << endl;
00566     kdDebug() << "\n\n" << endl;
00567 #endif
00568     return stacking;
00569     }
00570 
00571 void Workspace::blockStackingUpdates( bool block )
00572     {
00573     if( block )
00574         {
00575         if( block_stacking_updates == 0 )
00576             blocked_propagating_new_clients = false;
00577         ++block_stacking_updates;
00578         }
00579     else // !block
00580         if( --block_stacking_updates == 0 )
00581             updateStackingOrder( blocked_propagating_new_clients );
00582     }
00583 
00584 // Ensure list is in stacking order
00585 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00586     {
00587 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00588     if( list.count() < 2 )
00589         return list;
00590     // TODO is this worth optimizing?
00591     ClientList result = list;
00592     for( ClientList::ConstIterator it = stacking_order.begin();
00593          it != stacking_order.end();
00594          ++it )
00595         if( result.remove( *it ) != 0 )
00596             result.append( *it );
00597     return result;
00598     }
00599 
00600 // check whether a transient should be actually kept above its mainwindow
00601 // there may be some special cases where this rule shouldn't be enfored
00602 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00603     {
00604     // When topmenu's mainwindow becomes active, topmenu is raised and shown.
00605     // They also belong to the Dock layer. This makes them to be very high.
00606     // Therefore don't keep group transients above them, otherwise this would move
00607     // group transients way too high.
00608     if( mainwindow->isTopMenu() && transient->groupTransient())
00609         return false;
00610     // #93832 - don't keep splashscreens above dialogs
00611     if( transient->isSplash() && mainwindow->isDialog())
00612         return false;
00613     // This is rather a hack for #76026. Don't keep non-modal dialogs above
00614     // the mainwindow, but only if they're group transient (since only such dialogs
00615     // have taskbar entry in Kicker). A proper way of doing this (both kwin and kicker)
00616     // needs to be found.
00617     if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
00618         return false;
00619     return true;
00620     // #63223 - don't keep transients above docks, because the dock is kept high,
00621     // and e.g. dialogs for them would be too high too
00622     // TODO this doesn't really work - the transient should be raised after clicking
00623     // on the dock, but docks don't become active after clicking them
00624     if( mainwindow->isDock() && !mainwindow->keepBelow()
00625         && !mainwindow->isActive() && !transient->isActive()) // TODO !w->group()->isActive() ???
00626         return false;
00627     return true;
00628     }
00629 
00630 //*******************************
00631 // Client
00632 //*******************************
00633 
00634 void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event )
00635     {
00636     switch ( detail )
00637         {
00638         case Above:
00639         case TopIf:
00640             workspace()->raiseClientRequest( this, src, timestamp );
00641           break;
00642         case Below:
00643         case BottomIf:
00644             workspace()->lowerClientRequest( this, src, timestamp );
00645           break;
00646         case Opposite:
00647         default:
00648             break;
00649         }
00650     if( send_event )
00651         sendSyntheticConfigureNotify();
00652     }
00653     
00654 void Client::setKeepAbove( bool b )
00655     {
00656     b = rules()->checkKeepAbove( b );
00657     if( b )
00658         setKeepBelow( false );
00659     if ( b == keepAbove()
00660         || ( b && keepBelow())) // forced below
00661         { // force hint change if different
00662         if( bool( info->state() & NET::KeepAbove ) != keepAbove())
00663             info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00664         return;
00665         }
00666     keep_above = b;
00667     info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00668     if( decoration != NULL )
00669         decoration->emitKeepAboveChanged( keepAbove());
00670     workspace()->updateClientLayer( this );
00671     updateWindowRules();
00672     }
00673 
00674 void Client::setKeepBelow( bool b )
00675     {
00676     b = rules()->checkKeepBelow( b );
00677     if( b )
00678         setKeepAbove( false );
00679     if ( b == keepBelow()
00680         || ( b && keepAbove())) // forced above
00681         { // force hint change if different
00682         if( bool( info->state() & NET::KeepBelow ) != keepBelow())
00683             info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00684         return;
00685         }
00686     keep_below = b;
00687     info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00688     if( decoration != NULL )
00689         decoration->emitKeepBelowChanged( keepBelow());
00690     workspace()->updateClientLayer( this );
00691     updateWindowRules();
00692     }
00693 
00694 Layer Client::layer() const
00695     {
00696     if( in_layer == UnknownLayer )
00697         const_cast< Client* >( this )->in_layer = belongsToLayer();
00698     return in_layer;
00699     }
00700 
00701 Layer Client::belongsToLayer() const
00702     {
00703     if( isDesktop())
00704         return DesktopLayer;
00705     if( isSplash())         // no damn annoying splashscreens
00706         return NormalLayer; // getting in the way of everything else
00707     if( isDock() && keepBelow())
00708         // slight hack for the 'allow window to cover panel' Kicker setting
00709         // don't move keepbelow docks below normal window, but only to the same
00710         // layer, so that both may be raised to cover the other
00711         return NormalLayer;
00712     if( keepBelow())
00713         return BelowLayer;
00714     if( isDock() && !keepBelow())
00715         return DockLayer;
00716     if( isTopMenu())
00717         return DockLayer;
00718     // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
00719     // i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
00720     const Client* ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker
00721     if( isFullScreen() && ac != NULL
00722         && workspace()->topClientOnDesktop( desktop(), true ) == ac
00723         && ( ac == this || this->hasTransient( ac, true )))
00724         return ActiveLayer;
00725     if( keepAbove())
00726         return AboveLayer;
00727     return NormalLayer;
00728     }
00729 
00730 } // namespace
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Aug 20 13:39:13 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003