• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KWin

layers.cpp

Go to the documentation of this file.
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 This program is free software; you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation; either version 2 of the License, or
00011 (at your option) any later version.
00012 
00013 This program is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020 *********************************************************************/
00021 
00022 // SELI zmenit doc
00023 
00024 /*
00025 
00026  This file contains things relevant to stacking order and layers.
00027 
00028  Design:
00029 
00030  Normal unconstrained stacking order, as requested by the user (by clicking
00031  on windows to raise them, etc.), is in Workspace::unconstrained_stacking_order.
00032  That list shouldn't be used at all, except for building
00033  Workspace::stacking_order. The building is done
00034  in Workspace::constrainedStackingOrder(). Only Workspace::stackingOrder() should
00035  be used to get the stacking order, because it also checks the stacking order
00036  is up to date.
00037  All clients are also stored in Workspace::clients (except for isDesktop() clients,
00038  as those are very special, and are stored in Workspace::desktops), in the order
00039  the clients were created.
00040 
00041  Every window has one layer assigned in which it is. There are 6 layers,
00042  from bottom : DesktopLayer, BelowLayer, NormalLayer, DockLayer, AboveLayer
00043  and ActiveLayer (see also NETWM sect.7.10.). The layer a window is in depends
00044  on the window type, and on other things like whether the window is active.
00045 
00046  NET::Splash clients belong to the Normal layer. NET::TopMenu clients
00047  belong to Dock layer. Clients that are both NET::Dock and NET::KeepBelow
00048  are in the Normal layer in order to keep the 'allow window to cover
00049  the panel' Kicker setting to work as intended (this may look like a slight
00050  spec violation, but a) I have no better idea, b) the spec allows adjusting
00051  the stacking order if the WM thinks it's a good idea . We put all
00052  NET::KeepAbove above all Docks too, even though the spec suggests putting
00053  them in the same layer.
00054 
00055  Most transients are in the same layer as their mainwindow,
00056  see Workspace::constrainedStackingOrder(), they may also be in higher layers, but
00057  they should never be below their mainwindow.
00058 
00059  When some client attribute changes (above/below flag, transiency...),
00060  Workspace::updateClientLayer() should be called in order to make
00061  sure it's moved to the appropriate layer ClientList if needed.
00062 
00063  Currently the things that affect client in which layer a client
00064  belongs: KeepAbove/Keep Below flags, window type, fullscreen
00065  state and whether the client is active, mainclient (transiency).
00066 
00067  Make sure updateStackingOrder() is called in order to make
00068  Workspace::stackingOrder() up to date and propagated to the world.
00069  Using Workspace::blockStackingUpdates() (or the StackingUpdatesBlocker
00070  helper class) it's possible to temporarily disable updates
00071  and the stacking order will be updated once after it's allowed again.
00072 
00073 */
00074 
00075 #include <assert.h>
00076 
00077 #include <kdebug.h>
00078 
00079 #include "utils.h"
00080 #include "client.h"
00081 #include "workspace.h"
00082 #include "tabbox.h"
00083 #include "group.h"
00084 #include "rules.h"
00085 #include "unmanaged.h"
00086 #include "deleted.h"
00087 #include <QX11Info>
00088 
00089 namespace KWin
00090 {
00091 
00092 //*******************************
00093 // Workspace
00094 //*******************************
00095 
00096 void Workspace::updateClientLayer( Client* c )
00097     {
00098     if( c == NULL )
00099         return;
00100     if( c->layer() == c->belongsToLayer())
00101         return;
00102     StackingUpdatesBlocker blocker( this );
00103     c->invalidateLayer(); // invalidate, will be updated when doing restacking
00104     for( ClientList::ConstIterator it = c->transients().constBegin();
00105          it != c->transients().constEnd();
00106          ++it )
00107         updateClientLayer( *it );
00108     }
00109 
00110 void Workspace::updateStackingOrder( bool propagate_new_clients )
00111     {
00112     if( block_stacking_updates > 0 )
00113         {
00114         if( propagate_new_clients )
00115             blocked_propagating_new_clients = true;
00116         return;
00117         }
00118     ClientList new_stacking_order = constrainedStackingOrder();
00119     bool changed = ( new_stacking_order != stacking_order || force_restacking );
00120     force_restacking = false;
00121     stacking_order = new_stacking_order;
00122 #if 0
00123     kDebug(1212) << "stacking:" << changed;
00124     if( changed || propagate_new_clients )
00125         {
00126         for( ClientList::ConstIterator it = stacking_order.begin();
00127              it != stacking_order.end();
00128              ++it )
00129             kDebug(1212) << (void*)(*it) << *it << ":" << (*it)->layer();
00130         }
00131 #endif
00132     if( changed || propagate_new_clients )
00133         {
00134         propagateClients( propagate_new_clients );
00135         addRepaintFull();
00136         if( active_client )
00137             active_client->updateMouseGrab();
00138         }
00139     }
00140 
00145 void Workspace::propagateClients( bool propagate_new_clients )
00146     {
00147     Window *cl; // MW we should not assume WId and Window to be compatible
00148                                 // when passig pointers around.
00149 
00150     // restack the windows according to the stacking order
00151     // 1 - supportWindow, 1 - topmenu_space, 8 - electric borders
00152     Window* new_stack = new Window[ stacking_order.count() + 1 + 1 + 8 ];
00153     int pos = 0;
00154     // Stack all windows under the support window. The support window is
00155     // not used for anything (besides the NETWM property), and it's not shown,
00156     // but it was lowered after kwin startup. Stacking all clients below
00157     // it ensures that no client will be ever shown above override-redirect
00158     // windows (e.g. popups).
00159     new_stack[ pos++ ] = supportWindow->winId();
00160     for( int i = 0;
00161          i < ELECTRIC_COUNT;
00162          ++i )
00163         if( electric_windows[ i ] != None )
00164             new_stack[ pos++ ] = electric_windows[ i ];
00165     int topmenu_space_pos = 1; // not 0, that's supportWindow !!!
00166     for ( int i = stacking_order.size() - 1; i >= 0; i-- )
00167         {
00168         if( stacking_order.at( i )->hiddenPreview())
00169             continue;
00170         new_stack[ pos++ ] = stacking_order.at( i )->frameId();
00171         if( stacking_order.at( i )->belongsToLayer() >= DockLayer )
00172             topmenu_space_pos = pos;
00173         }
00174     if( topmenu_space != NULL )
00175         { // make sure the topmenu space is below all topmenus, fullscreens, etc.
00176         for( int i = pos;
00177              i > topmenu_space_pos;
00178              --i )
00179             new_stack[ i ] = new_stack[ i - 1 ];
00180         new_stack[ topmenu_space_pos ] = topmenu_space->winId();
00181         ++pos;
00182         }
00183     // when having hidden previews, stack hidden windows below everything else
00184     // (as far as pure X stacking order is concerned), in order to avoid having
00185     // these windows that should be unmapped to interfere with other windows
00186     for ( int i = stacking_order.size() - 1; i >= 0; i-- )
00187         {
00188         if( !stacking_order.at( i )->hiddenPreview())
00189             continue;
00190         new_stack[ pos++ ] = stacking_order.at( i )->frameId();
00191         if( stacking_order.at( i )->belongsToLayer() >= DockLayer )
00192             topmenu_space_pos = pos;
00193         }
00194     // TODO isn't it too inefficient to restack always all clients?
00195     // TODO don't restack not visible windows?
00196     assert( new_stack[ 0 ] == supportWindow->winId());
00197     XRestackWindows(display(), new_stack, pos);
00198     delete [] new_stack;
00199 
00200     if ( propagate_new_clients )
00201         {
00202         cl = new Window[ desktops.count() + clients.count()];
00203         pos = 0;
00204     // TODO this is still not completely in the map order
00205         for ( ClientList::ConstIterator it = desktops.constBegin(); it != desktops.constEnd(); ++it )
00206             cl[pos++] =  (*it)->window();
00207         for ( ClientList::ConstIterator it = clients.constBegin(); it != clients.constEnd(); ++it )
00208             cl[pos++] =  (*it)->window();
00209         rootInfo->setClientList( cl, pos );
00210         delete [] cl;
00211         }
00212 
00213     cl = new Window[ stacking_order.count()];
00214     pos = 0;
00215     for ( ClientList::ConstIterator it = stacking_order.constBegin(); it != stacking_order.constEnd(); ++it)
00216         cl[pos++] =  (*it)->window();
00217     rootInfo->setClientListStacking( cl, pos );
00218     delete [] cl;
00219     
00220     // Make the cached stacking order invalid here, in case we need the new stacking order before we get
00221     // the matching event, due to X being asynchronous.
00222     x_stacking_dirty = true; 
00223     }
00224 
00225 
00231 // TODO misleading name for this method, too many slightly different ways to use it
00232 Client* Workspace::topClientOnDesktop( int desktop, int screen, bool unconstrained, bool only_normal ) const
00233     {
00234 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00235     ClientList list;
00236     if( !unconstrained )
00237         list = stacking_order;
00238     else
00239         list = unconstrained_stacking_order;
00240     for( int i = list.size() - 1;
00241          i >= 0;
00242          --i )
00243         {
00244         if( list.at( i )->isOnDesktop( desktop ) && list.at( i )->isShown( false ))
00245             {
00246             if( screen != -1 && list.at( i )->screen() != screen )
00247                 continue;
00248             if( !only_normal )
00249                 return list.at( i );
00250             if( list.at( i )->wantsTabFocus() && !list.at( i )->isSpecialWindow())
00251                 return list.at( i );
00252             }
00253         }
00254     return 0;
00255     }
00256 
00257 Client* Workspace::findDesktop( bool topmost, int desktop ) const
00258     {
00259 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00260     if( topmost )
00261         {
00262         for ( int i = stacking_order.size() - 1; i>=0; i-- )
00263             {
00264             if ( stacking_order.at( i )->isOnDesktop( desktop ) && stacking_order.at( i )->isDesktop()
00265                 && stacking_order.at( i )->isShown( true ))
00266                 return stacking_order.at(  i );
00267             }
00268         }
00269     else // bottom-most
00270         {
00271         foreach ( Client* c, stacking_order )
00272             {
00273             if ( c->isOnDesktop( desktop ) && c->isDesktop()
00274                 && c->isShown( true ))
00275                 return c;
00276             }
00277         }
00278     return NULL;
00279     }
00280 
00281 void Workspace::raiseOrLowerClient( Client *c)
00282     {
00283     if (!c) return;
00284     Client* topmost = NULL;
00285 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00286     if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
00287          most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
00288         topmost = most_recently_raised;
00289     else
00290         topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop(),
00291             options->separateScreenFocus ? c->screen() : -1 );
00292 
00293     if( c == topmost)
00294         lowerClient(c);
00295     else
00296         raiseClient(c);
00297     }
00298 
00299 
00300 void Workspace::lowerClient( Client* c, bool nogroup )
00301     {
00302     if ( !c )
00303         return;
00304     if( c->isTopMenu())
00305         return;
00306 
00307     c->cancelAutoRaise();
00308 
00309     StackingUpdatesBlocker blocker( this );
00310 
00311     unconstrained_stacking_order.removeAll( c );
00312     unconstrained_stacking_order.prepend( c );
00313     if( !nogroup && c->isTransient() )
00314         {
00315         // lower also all windows in the group, in their reversed stacking order
00316         ClientList wins = ensureStackingOrder( c->group()->members());
00317         for( int i = wins.size() - 1;
00318              i >= 0;
00319              --i )
00320             {
00321             if( wins[ i ] != c )
00322                 lowerClient( wins[ i ], true );
00323             }
00324         }
00325 
00326     if ( c == most_recently_raised )
00327         most_recently_raised = 0;
00328     }
00329 
00330 void Workspace::lowerClientWithinApplication( Client* c )
00331     {
00332     if ( !c )
00333         return;
00334     if( c->isTopMenu())
00335         return;
00336 
00337     c->cancelAutoRaise();
00338 
00339     StackingUpdatesBlocker blocker( this );
00340 
00341     unconstrained_stacking_order.removeAll( c );
00342     bool lowered = false;
00343     // first try to put it below the bottom-most window of the application
00344     for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00345          it != unconstrained_stacking_order.end();
00346          ++it )
00347         if( Client::belongToSameApplication( *it, c ))
00348             {
00349             unconstrained_stacking_order.insert( it, c );
00350             lowered = true;
00351             break;
00352             }
00353     if( !lowered )
00354         unconstrained_stacking_order.prepend( c );
00355     // ignore mainwindows
00356     }
00357 
00358 void Workspace::raiseClient( Client* c, bool nogroup )
00359     {
00360     if ( !c )
00361         return;
00362     if( c->isTopMenu())
00363         return;
00364 
00365     c->cancelAutoRaise();
00366 
00367     StackingUpdatesBlocker blocker( this );
00368 
00369     if( !nogroup && c->isTransient())
00370         {
00371         ClientList wins = ensureStackingOrder( c->group()->members());
00372         foreach( Client* c2, wins )
00373             if( c2 != c )
00374                 raiseClient( c2, true );
00375         }
00376 
00377     unconstrained_stacking_order.removeAll( c );
00378     unconstrained_stacking_order.append( c );
00379 
00380     if( !c->isSpecialWindow())
00381         {
00382         most_recently_raised = c;
00383         pending_take_activity = NULL;
00384         }
00385     }
00386 
00387 void Workspace::raiseClientWithinApplication( Client* c )
00388     {
00389     if ( !c )
00390         return;
00391     if( c->isTopMenu())
00392         return;
00393 
00394     c->cancelAutoRaise();
00395 
00396     StackingUpdatesBlocker blocker( this );
00397     // ignore mainwindows
00398     
00399     // first try to put it above the top-most window of the application
00400     for ( int i = unconstrained_stacking_order.size() - 1; i>= 0 ; i-- )
00401         {
00402         if( unconstrained_stacking_order.at( i ) == c ) // don't lower it just because it asked to be raised
00403             return;
00404         if( Client::belongToSameApplication( unconstrained_stacking_order.at(  i ), c ))
00405             {
00406             unconstrained_stacking_order.removeAll( c );
00407             unconstrained_stacking_order.insert( ++i, c ); // insert after the found one
00408             return;
00409             }
00410         }
00411     }
00412 
00413 void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp )
00414     {
00415     if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
00416         raiseClient( c );
00417     else
00418         {
00419         raiseClientWithinApplication( c );
00420         c->demandAttention();
00421         }
00422     }
00423 
00424 void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time /*timestamp*/ )
00425     {
00426     // If the client has support for all this focus stealing prevention stuff,
00427     // do only lowering within the application, as that's the more logical
00428     // variant of lowering when application requests it.
00429     // No demanding of attention here of course.
00430     if( src == NET::FromTool || !c->hasUserTimeSupport())
00431         lowerClient( c );
00432     else
00433         lowerClientWithinApplication( c );
00434     }
00435 
00436 void Workspace::restackClientUnderActive( Client* c )
00437     {
00438     if( c->isTopMenu())
00439         return;
00440     if( !active_client || active_client == c )
00441         {
00442         raiseClient( c );
00443         return;
00444         }
00445 
00446     assert( unconstrained_stacking_order.contains( active_client ));
00447     if( Client::belongToSameApplication( active_client, c ))
00448         { // put it below the active window if it's the same app
00449         unconstrained_stacking_order.removeAll( c );
00450         unconstrained_stacking_order.insert( unconstrained_stacking_order.indexOf( active_client ), c );
00451         }
00452     else
00453         { // put in the stacking order below _all_ windows belonging to the active application
00454         for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00455              it != unconstrained_stacking_order.end();
00456              ++it )
00457             { // TODO ignore topmenus?
00458             if( Client::belongToSameApplication( active_client, *it ))
00459                 {
00460                 if( *it != c )
00461                     {
00462                     unconstrained_stacking_order.removeAll( c );
00463                     unconstrained_stacking_order.insert( it, c );
00464                     }
00465                 break;
00466                 }
00467             }
00468         }
00469     assert( unconstrained_stacking_order.contains( c ));
00470     for( int desktop = 1;
00471          desktop <= numberOfDesktops();
00472          ++desktop )
00473         { // do for every virtual desktop to handle the case of onalldesktop windows
00474         if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client ))
00475             {
00476             if( Client::belongToSameApplication( active_client, c ))
00477                 { // put it after the active window if it's the same app
00478                 focus_chain[ desktop ].removeAll( c );
00479                 focus_chain[ desktop ].insert( focus_chain[ desktop ].indexOf( active_client ), c );
00480                 }
00481             else
00482                 { // put it in focus_chain[currentDesktop()] after all windows belonging to the active applicationa
00483                 focus_chain[ desktop ].removeAll( c );
00484                 for( int i = focus_chain[ desktop ].size() - 1;
00485                      i >= 0;
00486                      --i )
00487                     {
00488                     if( Client::belongToSameApplication( active_client, focus_chain[ desktop ].at( i )))
00489                         {
00490                         focus_chain[ desktop ].insert( i, c );
00491                         break;
00492                         }
00493                     }
00494                 }
00495             }
00496         }
00497     // the same for global_focus_chain
00498     if( c->wantsTabFocus() && global_focus_chain.contains( active_client ))
00499         {
00500         if( Client::belongToSameApplication( active_client, c ))
00501             {
00502             global_focus_chain.removeAll( c );
00503             global_focus_chain.insert( global_focus_chain.indexOf( active_client ), c );
00504             }
00505         else
00506             {
00507             global_focus_chain.removeAll( c );
00508             for ( int i = global_focus_chain.size() - 1;
00509                   i >= 0;
00510                   --i )
00511                 {
00512                 if( Client::belongToSameApplication( active_client, global_focus_chain.at( i ) ))
00513                     {
00514                     global_focus_chain.insert( i, c );
00515                     break;
00516                     }
00517                 }
00518             }
00519         }
00520     updateStackingOrder();
00521     }
00522 
00523 void Workspace::restoreSessionStackingOrder( Client* c )
00524     {
00525     if( c->sessionStackingOrder() < 0 )
00526         return;
00527     StackingUpdatesBlocker blocker( this );
00528     unconstrained_stacking_order.removeAll( c );
00529     ClientList::Iterator best_pos = unconstrained_stacking_order.end();
00530     for( ClientList::Iterator it = unconstrained_stacking_order.begin(); // from bottom
00531          it != unconstrained_stacking_order.end();
00532          ++it )
00533         {
00534         if( (*it)->sessionStackingOrder() > c->sessionStackingOrder() )
00535             {
00536             unconstrained_stacking_order.insert( it, c );
00537             return;
00538             }
00539         }
00540     unconstrained_stacking_order.append( c );
00541     }
00542 
00543 void Workspace::circulateDesktopApplications()
00544     {
00545     if ( desktops.count() > 1 )
00546         {
00547         bool change_active = activeClient()->isDesktop();
00548         raiseClient( findDesktop( false, currentDesktop()));
00549         if( change_active ) // if the previously topmost Desktop was active, activate this new one
00550             activateClient( findDesktop( true, currentDesktop()));
00551         }
00552     // if there's no active client, make desktop the active one
00553     if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00554         activateClient( findDesktop( true, currentDesktop()));
00555     }
00556 
00557 
00561 ClientList Workspace::constrainedStackingOrder()
00562     {
00563     ClientList layer[ NumLayers ];
00564 
00565 #if 0
00566     kDebug(1212) << "stacking1:";
00567     for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00568          it != unconstrained_stacking_order.end();
00569          ++it )
00570         kDebug(1212) << (void*)(*it) << *it << ":" << (*it)->layer();
00571 #endif
00572     // build the order from layers
00573     QHash< Group*, Layer > minimum_layer;
00574     for( ClientList::ConstIterator it = unconstrained_stacking_order.constBegin();
00575          it != unconstrained_stacking_order.constEnd();
00576          ++it )
00577         {
00578         Layer l = (*it)->layer();
00579         // If a window is raised above some other window in the same window group
00580         // which is in the ActiveLayer (i.e. it's fulscreened), make sure it stays
00581         // above that window (see #95731).
00582         if( minimum_layer.contains( (*it)->group())
00583             && minimum_layer[ (*it)->group() ] == ActiveLayer
00584             && ( l == NormalLayer || l == AboveLayer ))
00585             {
00586             l = minimum_layer[ (*it)->group() ];
00587             }
00588         minimum_layer[ (*it)->group() ] = l;
00589         layer[ l ].append( *it );
00590         }
00591     ClientList stacking;    
00592     for( Layer lay = FirstLayer;
00593          lay < NumLayers;
00594          ++lay )    
00595         stacking += layer[ lay ];
00596 #if 0
00597     kDebug(1212) << "stacking2:";
00598     for( ClientList::ConstIterator it = stacking.begin();
00599          it != stacking.end();
00600          ++it )
00601         kDebug(1212) << (void*)(*it) << *it << ":" << (*it)->layer();
00602 #endif
00603     // now keep transients above their mainwindows
00604     // TODO this could(?) use some optimization
00605     for( int i = stacking.size() - 1;
00606          i >= 0;
00607          )
00608         {
00609         if( !stacking[ i ]->isTransient())
00610             {
00611             --i;
00612             continue;
00613             }
00614         int i2 = -1;
00615         if( stacking[ i ]->groupTransient())
00616             {
00617             if( stacking[ i ]->group()->members().count() > 0 )
00618                 { // find topmost client this one is transient for
00619                 for( i2 = stacking.size() - 1;
00620                      i2 >= 0;
00621                      --i2 )
00622                     {
00623                     if( stacking[ i2 ] == stacking[ i ] )
00624                         {
00625                         i2 = -1; // don't reorder, already the topmost in the group
00626                         break;
00627                         }
00628                     if( stacking[ i2 ]->hasTransient( stacking[ i ], true )
00629                         && keepTransientAbove( stacking[ i2 ], stacking[ i ] ))
00630                         break;
00631                     }
00632                 } // else i2 remains pointing at -1
00633             }
00634         else
00635             {
00636             for( i2 = stacking.size() - 1;
00637                  i2 >= 0;
00638                  --i2 )
00639                 {
00640                 if( stacking[ i2 ] == stacking[ i ] )
00641                     {
00642                     i2 = -1; // don't reorder, already on top of its mainwindow
00643                     break;
00644                     }
00645                 if( stacking[ i2 ] == stacking[ i ]->transientFor()
00646                     && keepTransientAbove( stacking[ i2 ], stacking[ i ] ))
00647                     break;
00648                 }
00649             }
00650         if( i2 == -1 )
00651             {
00652             --i;
00653             continue;
00654             }
00655         Client* current = stacking[ i ];
00656         stacking.removeAt( i );
00657         --i; // move onto the next item (for next for() iteration)
00658         --i2; // adjust index of the mainwindow after the remove above
00659         if( !current->transients().isEmpty())  // this one now can be possibly above its transients,
00660             i = i2; // so go again higher in the stack order and possibly move those transients again
00661         ++i2; // insert after (on top of) the mainwindow, it's ok if it2 is now stacking.end()
00662         stacking.insert( i2, current );
00663         }
00664 #if 0
00665     kDebug(1212) << "stacking3:";
00666     for( ClientList::ConstIterator it = stacking.begin();
00667          it != stacking.end();
00668          ++it )
00669         kDebug(1212) << (void*)(*it) << *it << ":" << (*it)->layer();
00670     kDebug(1212) << "\n\n";
00671 #endif
00672     return stacking;
00673     }
00674 
00675 void Workspace::blockStackingUpdates( bool block )
00676     {
00677     if( block )
00678         {
00679         if( block_stacking_updates == 0 )
00680             blocked_propagating_new_clients = false;
00681         ++block_stacking_updates;
00682         }
00683     else // !block
00684         if( --block_stacking_updates == 0 )
00685             updateStackingOrder( blocked_propagating_new_clients );
00686     }
00687 
00688 // Ensure list is in stacking order
00689 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00690     {
00691 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00692     if( list.count() < 2 )
00693         return list;
00694     // TODO is this worth optimizing?
00695     ClientList result = list;
00696     for( ClientList::ConstIterator it = stacking_order.constBegin();
00697          it != stacking_order.constEnd();
00698          ++it )
00699         if( result.removeAll( *it ) != 0 )
00700             result.append( *it );
00701     return result;
00702     }
00703 
00704 // check whether a transient should be actually kept above its mainwindow
00705 // there may be some special cases where this rule shouldn't be enfored
00706 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00707     {
00708     // When topmenu's mainwindow becomes active, topmenu is raised and shown.
00709     // They also belong to the Dock layer. This makes them to be very high.
00710     // Therefore don't keep group transients above them, otherwise this would move
00711     // group transients way too high.
00712     if( mainwindow->isTopMenu() && transient->groupTransient())
00713         return false;
00714     // #93832 - don't keep splashscreens above dialogs
00715     if( transient->isSplash() && mainwindow->isDialog())
00716         return false;
00717     // This is rather a hack for #76026. Don't keep non-modal dialogs above
00718     // the mainwindow, but only if they're group transient (since only such dialogs
00719     // have taskbar entry in Kicker). A proper way of doing this (both kwin and kicker)
00720     // needs to be found.
00721     if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
00722         return false;
00723     // #63223 - don't keep transients above docks, because the dock is kept high,
00724     // and e.g. dialogs for them would be too high too
00725     if( mainwindow->isDock())
00726         return false;
00727     return true;
00728     }
00729 
00730 // Returns all windows in their stacking order on the root window.
00731 ToplevelList Workspace::xStackingOrder() const
00732     {
00733     if( !x_stacking_dirty )
00734         return x_stacking;
00735     x_stacking_dirty = false;
00736     x_stacking.clear();
00737     Window dummy;
00738     Window* windows = NULL;
00739     unsigned int count = 0;
00740     XQueryTree( display(), rootWindow(), &dummy, &dummy, &windows, &count );
00741     // use our own stacking order, not the X one, as they may differ
00742     foreach( Client* c, stacking_order )
00743         x_stacking.append( c );
00744     for( unsigned int i = 0;
00745          i < count;
00746          ++i )
00747         {
00748         if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( windows[ i ] )))
00749             x_stacking.append( c );
00750         }
00751     foreach( Deleted* c, deleted )
00752         x_stacking.append( c );
00753     if( windows != NULL )
00754         XFree( windows );
00755     const_cast< Workspace* >( this )->checkUnredirect();
00756     return x_stacking;
00757     }
00758 
00759 //*******************************
00760 // Client
00761 //*******************************
00762 
00763 void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event )
00764     {
00765     switch ( detail )
00766         {
00767         case Above:
00768         case TopIf:
00769             workspace()->raiseClientRequest( this, src, timestamp );
00770           break;
00771         case Below:
00772         case BottomIf:
00773             workspace()->lowerClientRequest( this, src, timestamp );
00774           break;
00775         case Opposite:
00776         default:
00777             break;
00778         }
00779     if( send_event )
00780         sendSyntheticConfigureNotify();
00781     }
00782     
00783 void Client::setKeepAbove( bool b )
00784     {
00785     b = rules()->checkKeepAbove( b );
00786     if( b && !rules()->checkKeepBelow( false ))
00787         setKeepBelow( false );
00788     if ( b == keepAbove())
00789         { // force hint change if different
00790         if( bool( info->state() & NET::KeepAbove ) != keepAbove())
00791             info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00792         return;
00793         }
00794     keep_above = b;
00795     info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00796     if( decoration != NULL )
00797         decoration->emitKeepAboveChanged( keepAbove());
00798     workspace()->updateClientLayer( this );
00799     updateWindowRules();
00800     }
00801 
00802 void Client::setKeepBelow( bool b )
00803     {
00804     b = rules()->checkKeepBelow( b );
00805     if( b && !rules()->checkKeepAbove( false ))
00806         setKeepAbove( false );
00807     if ( b == keepBelow())
00808         { // force hint change if different
00809         if( bool( info->state() & NET::KeepBelow ) != keepBelow())
00810             info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00811         return;
00812         }
00813     keep_below = b;
00814     info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00815     if( decoration != NULL )
00816         decoration->emitKeepBelowChanged( keepBelow());
00817     workspace()->updateClientLayer( this );
00818     updateWindowRules();
00819     }
00820 
00821 Layer Client::layer() const
00822     {
00823     if( in_layer == UnknownLayer )
00824         const_cast< Client* >( this )->in_layer = belongsToLayer();
00825     return in_layer;
00826     }
00827 
00828 Layer Client::belongsToLayer() const
00829     {
00830     if( isDesktop())
00831         return DesktopLayer;
00832     if( isSplash())         // no damn annoying splashscreens
00833         return NormalLayer; // getting in the way of everything else
00834     if( isDock() && keepBelow())
00835         // slight hack for the 'allow window to cover panel' Kicker setting
00836         // don't move keepbelow docks below normal window, but only to the same
00837         // layer, so that both may be raised to cover the other
00838         return NormalLayer;
00839     if( keepBelow())
00840         return BelowLayer;
00841     if( isDock() && !keepBelow())
00842         return DockLayer;
00843     if( isTopMenu())
00844         return DockLayer;
00845     if( isActiveFullScreen())
00846         return ActiveLayer;
00847     if( keepAbove())
00848         return AboveLayer;
00849     return NormalLayer;
00850     }
00851 
00852 bool Client::isActiveFullScreen() const
00853     {
00854     // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
00855     // i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
00856     const Client* ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker
00857     const Client* top = workspace()->topClientOnDesktop( workspace()->currentDesktop(), screen(), true, false );
00858     return( isFullScreen() && ac != NULL && top != NULL
00859 // not needed, for xinerama  && ( ac == this || this->group() == ac->group())
00860         && ( top == this || this->group() == top->group()));
00861     }
00862 
00863 } // namespace

KWin

Skip menu "KWin"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal