• Skip to content
  • Skip to link menu
KDE 4.1 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().begin();
00105          it != c->transients().end();
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() << "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() << (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.begin(); it != desktops.end(); ++it )
00206             cl[pos++] =  (*it)->window();
00207         for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++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.begin(); it != stacking_order.end(); ++it)
00216         cl[pos++] =  (*it)->window();
00217     rootInfo->setClientListStacking( cl, pos );
00218     delete [] cl;
00219     }
00220 
00221 
00227 // TODO misleading name for this method
00228 Client* Workspace::topClientOnDesktop( int desktop, bool unconstrained, bool only_normal ) const
00229     {
00230 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00231     ClientList list;
00232     if( !unconstrained )
00233         list = stacking_order;
00234     else
00235         list = unconstrained_stacking_order;
00236     for( int i = list.size() - 1;
00237          i >= 0;
00238          --i )
00239         {
00240         if( list.at( i )->isOnDesktop( desktop ) && list.at( i )->isShown( false ))
00241             {
00242             if( !only_normal )
00243                 return list.at( i );
00244             if( list.at( i )->wantsTabFocus() && !list.at( i )->isSpecialWindow())
00245                 return list.at( i );
00246             }
00247         }
00248     return 0;
00249     }
00250 
00251 Client* Workspace::findDesktop( bool topmost, int desktop ) const
00252     {
00253 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00254     if( topmost )
00255         {
00256         for ( int i = stacking_order.size() - 1; i>=0; i-- )
00257             {
00258             if ( stacking_order.at( i )->isOnDesktop( desktop ) && stacking_order.at( i )->isDesktop()
00259                 && stacking_order.at( i )->isShown( true ))
00260                 return stacking_order.at(  i );
00261             }
00262         }
00263     else // bottom-most
00264         {
00265         foreach ( Client* c, stacking_order )
00266             {
00267             if ( c->isOnDesktop( desktop ) && c->isDesktop()
00268                 && c->isShown( true ))
00269                 return c;
00270             }
00271         }
00272     return NULL;
00273     }
00274 
00275 void Workspace::raiseOrLowerClient( Client *c)
00276     {
00277     if (!c) return;
00278     Client* topmost = NULL;
00279 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00280     if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
00281          most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
00282         topmost = most_recently_raised;
00283     else
00284         topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
00285 
00286     if( c == topmost)
00287         lowerClient(c);
00288     else
00289         raiseClient(c);
00290     }
00291 
00292 
00293 void Workspace::lowerClient( Client* c, bool nogroup )
00294     {
00295     if ( !c )
00296         return;
00297     if( c->isTopMenu())
00298         return;
00299 
00300     c->cancelAutoRaise();
00301 
00302     StackingUpdatesBlocker blocker( this );
00303 
00304     unconstrained_stacking_order.removeAll( c );
00305     unconstrained_stacking_order.prepend( c );
00306     if( !nogroup && c->isTransient() )
00307         {
00308         // lower also all windows in the group, in their reversed stacking order
00309         ClientList wins = ensureStackingOrder( c->group()->members());
00310         for( int i = wins.size() - 1;
00311              i >= 0;
00312              --i )
00313             {
00314             if( wins[ i ] != c )
00315                 lowerClient( wins[ i ], true );
00316             }
00317         }
00318 
00319     if ( c == most_recently_raised )
00320         most_recently_raised = 0;
00321     }
00322 
00323 void Workspace::lowerClientWithinApplication( Client* c )
00324     {
00325     if ( !c )
00326         return;
00327     if( c->isTopMenu())
00328         return;
00329 
00330     c->cancelAutoRaise();
00331 
00332     StackingUpdatesBlocker blocker( this );
00333 
00334     unconstrained_stacking_order.removeAll( c );
00335     bool lowered = false;
00336     // first try to put it below the bottom-most window of the application
00337     for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00338          it != unconstrained_stacking_order.end();
00339          ++it )
00340         if( Client::belongToSameApplication( *it, c ))
00341             {
00342             unconstrained_stacking_order.insert( it, c );
00343             lowered = true;
00344             break;
00345             }
00346     if( !lowered )
00347         unconstrained_stacking_order.prepend( c );
00348     // ignore mainwindows
00349     }
00350 
00351 void Workspace::raiseClient( Client* c, bool nogroup )
00352     {
00353     if ( !c )
00354         return;
00355     if( c->isTopMenu())
00356         return;
00357 
00358     c->cancelAutoRaise();
00359 
00360     StackingUpdatesBlocker blocker( this );
00361 
00362     if( !nogroup && c->isTransient())
00363         {
00364         ClientList wins = ensureStackingOrder( c->group()->members());
00365         foreach( Client* c2, wins )
00366             if( c2 != c )
00367                 raiseClient( c2, true );
00368         }
00369 
00370     unconstrained_stacking_order.removeAll( c );
00371     unconstrained_stacking_order.append( c );
00372 
00373     if( !c->isSpecialWindow())
00374         {
00375         most_recently_raised = c;
00376         pending_take_activity = NULL;
00377         }
00378     }
00379 
00380 void Workspace::raiseClientWithinApplication( Client* c )
00381     {
00382     if ( !c )
00383         return;
00384     if( c->isTopMenu())
00385         return;
00386 
00387     c->cancelAutoRaise();
00388 
00389     StackingUpdatesBlocker blocker( this );
00390     // ignore mainwindows
00391     
00392     // first try to put it above the top-most window of the application
00393     for ( int i = unconstrained_stacking_order.size() - 1; i>= 0 ; i-- )
00394         {
00395         if( unconstrained_stacking_order.at( i ) == c ) // don't lower it just because it asked to be raised
00396             return;
00397         if( Client::belongToSameApplication( unconstrained_stacking_order.at(  i ), c ))
00398             {
00399             unconstrained_stacking_order.removeAll( c );
00400             unconstrained_stacking_order.insert( ++i, c ); // insert after the found one
00401             return;
00402             }
00403         }
00404     }
00405 
00406 void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp )
00407     {
00408     if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
00409         raiseClient( c );
00410     else
00411         {
00412         raiseClientWithinApplication( c );
00413         c->demandAttention();
00414         }
00415     }
00416 
00417 void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time /*timestamp*/ )
00418     {
00419     // If the client has support for all this focus stealing prevention stuff,
00420     // do only lowering within the application, as that's the more logical
00421     // variant of lowering when application requests it.
00422     // No demanding of attention here of course.
00423     if( src == NET::FromTool || !c->hasUserTimeSupport())
00424         lowerClient( c );
00425     else
00426         lowerClientWithinApplication( c );
00427     }
00428 
00429 void Workspace::restackClientUnderActive( Client* c )
00430     {
00431     if( c->isTopMenu())
00432         return;
00433     if( !active_client || active_client == c )
00434         {
00435         raiseClient( c );
00436         return;
00437         }
00438 
00439     assert( unconstrained_stacking_order.contains( active_client ));
00440     if( Client::belongToSameApplication( active_client, c ))
00441         { // put it below the active window if it's the same app
00442         unconstrained_stacking_order.removeAll( c );
00443         unconstrained_stacking_order.insert( unconstrained_stacking_order.indexOf( active_client ), c );
00444         }
00445     else
00446         { // put in the stacking order below _all_ windows belonging to the active application
00447         for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00448              it != unconstrained_stacking_order.end();
00449              ++it )
00450             { // TODO ignore topmenus?
00451             if( Client::belongToSameApplication( active_client, *it ))
00452                 {
00453                 if( *it != c )
00454                     {
00455                     unconstrained_stacking_order.removeAll( c );
00456                     unconstrained_stacking_order.insert( it, c );
00457                     }
00458                 break;
00459                 }
00460             }
00461         }
00462     assert( unconstrained_stacking_order.contains( c ));
00463     for( int desktop = 1;
00464          desktop <= numberOfDesktops();
00465          ++desktop )
00466         { // do for every virtual desktop to handle the case of onalldesktop windows
00467         if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client ))
00468             {
00469             if( Client::belongToSameApplication( active_client, c ))
00470                 { // put it after the active window if it's the same app
00471                 focus_chain[ desktop ].removeAll( c );
00472                 focus_chain[ desktop ].insert( focus_chain[ desktop ].indexOf( active_client ), c );
00473                 }
00474             else
00475                 { // put it in focus_chain[currentDesktop()] after all windows belonging to the active applicationa
00476                 focus_chain[ desktop ].removeAll( c );
00477                 for( int i = focus_chain[ desktop ].size() - 1;
00478                      i >= 0;
00479                      --i )
00480                     {
00481                     if( Client::belongToSameApplication( active_client, focus_chain[ desktop ].at( i )))
00482                         {
00483                         focus_chain[ desktop ].insert( i, c );
00484                         break;
00485                         }
00486                     }
00487                 }
00488             }
00489         }
00490     // the same for global_focus_chain
00491     if( c->wantsTabFocus() && global_focus_chain.contains( active_client ))
00492         {
00493         if( Client::belongToSameApplication( active_client, c ))
00494             {
00495             global_focus_chain.removeAll( c );
00496             global_focus_chain.insert( global_focus_chain.indexOf( active_client ), c );
00497             }
00498         else
00499             {
00500             global_focus_chain.removeAll( c );
00501             for ( int i = global_focus_chain.size() - 1;
00502                   i >= 0;
00503                   --i )
00504                 {
00505                 if( Client::belongToSameApplication( active_client, global_focus_chain.at( i ) ))
00506                     {
00507                     global_focus_chain.insert( i, c );
00508                     break;
00509                     }
00510                 }
00511             }
00512         }
00513     updateStackingOrder();
00514     }
00515 
00516 void Workspace::restoreSessionStackingOrder( Client* c )
00517     {
00518     if( c->sessionStackingOrder() < 0 )
00519         return;
00520     StackingUpdatesBlocker blocker( this );
00521     unconstrained_stacking_order.removeAll( c );
00522     ClientList::Iterator best_pos = unconstrained_stacking_order.end();
00523     for( ClientList::Iterator it = unconstrained_stacking_order.begin(); // from bottom
00524          it != unconstrained_stacking_order.end();
00525          ++it )
00526         {
00527         if( (*it)->sessionStackingOrder() > c->sessionStackingOrder() )
00528             {
00529             unconstrained_stacking_order.insert( it, c );
00530             return;
00531             }
00532         }
00533     unconstrained_stacking_order.append( c );
00534     }
00535 
00536 void Workspace::circulateDesktopApplications()
00537     {
00538     if ( desktops.count() > 1 )
00539         {
00540         bool change_active = activeClient()->isDesktop();
00541         raiseClient( findDesktop( false, currentDesktop()));
00542         if( change_active ) // if the previously topmost Desktop was active, activate this new one
00543             activateClient( findDesktop( true, currentDesktop()));
00544         }
00545     // if there's no active client, make desktop the active one
00546     if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00547         activateClient( findDesktop( true, currentDesktop()));
00548     }
00549 
00550 
00554 ClientList Workspace::constrainedStackingOrder()
00555     {
00556     ClientList layer[ NumLayers ];
00557 
00558 #if 0
00559     kDebug() << "stacking1:";
00560     for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00561          it != unconstrained_stacking_order.end();
00562          ++it )
00563         kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer();
00564 #endif
00565     // build the order from layers
00566     QHash< Group*, Layer > minimum_layer;
00567     for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00568          it != unconstrained_stacking_order.end();
00569          ++it )
00570         {
00571         Layer l = (*it)->layer();
00572         // If a window is raised above some other window in the same window group
00573         // which is in the ActiveLayer (i.e. it's fulscreened), make sure it stays
00574         // above that window (see #95731).
00575         if( minimum_layer.contains( (*it)->group())
00576             && minimum_layer[ (*it)->group() ] == ActiveLayer
00577             && ( l == NormalLayer || l == AboveLayer ))
00578             {
00579             l = minimum_layer[ (*it)->group() ];
00580             }
00581         minimum_layer[ (*it)->group() ] = l;
00582         layer[ l ].append( *it );
00583         }
00584     ClientList stacking;    
00585     for( Layer lay = FirstLayer;
00586          lay < NumLayers;
00587          ++lay )    
00588         stacking += layer[ lay ];
00589 #if 0
00590     kDebug() << "stacking2:";
00591     for( ClientList::ConstIterator it = stacking.begin();
00592          it != stacking.end();
00593          ++it )
00594         kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer();
00595 #endif
00596     // now keep transients above their mainwindows
00597     // TODO this could(?) use some optimization
00598     for( int i = stacking.size() - 1;
00599          i >= 0;
00600          )
00601         {
00602         if( !stacking[ i ]->isTransient())
00603             {
00604             --i;
00605             continue;
00606             }
00607         int i2 = -1;
00608         if( stacking[ i ]->groupTransient())
00609             {
00610             if( stacking[ i ]->group()->members().count() > 0 )
00611                 { // find topmost client this one is transient for
00612                 for( i2 = stacking.size() - 1;
00613                      i2 >= 0;
00614                      --i2 )
00615                     {
00616                     if( stacking[ i2 ] == stacking[ i ] )
00617                         {
00618                         i2 = -1; // don't reorder, already the topmost in the group
00619                         break;
00620                         }
00621                     if( stacking[ i2 ]->hasTransient( stacking[ i ], true )
00622                         && keepTransientAbove( stacking[ i2 ], stacking[ i ] ))
00623                         break;
00624                     }
00625                 } // else i2 remains pointing at -1
00626             }
00627         else
00628             {
00629             for( i2 = stacking.size() - 1;
00630                  i2 >= 0;
00631                  --i2 )
00632                 {
00633                 if( stacking[ i2 ] == stacking[ i ] )
00634                     {
00635                     i2 = -1; // don't reorder, already on top of its mainwindow
00636                     break;
00637                     }
00638                 if( stacking[ i2 ] == stacking[ i ]->transientFor()
00639                     && keepTransientAbove( stacking[ i2 ], stacking[ i ] ))
00640                     break;
00641                 }
00642             }
00643         if( i2 == -1 )
00644             {
00645             --i;
00646             continue;
00647             }
00648         Client* current = stacking[ i ];
00649         stacking.removeAt( i );
00650         --i; // move onto the next item (for next for() iteration)
00651         --i2; // adjust index of the mainwindow after the remove above
00652         if( !current->transients().isEmpty())  // this one now can be possibly above its transients,
00653             i = i2; // so go again higher in the stack order and possibly move those transients again
00654         ++i2; // insert after (on top of) the mainwindow, it's ok if it2 is now stacking.end()
00655         stacking.insert( i2, current );
00656         }
00657 #if 0
00658     kDebug() << "stacking3:";
00659     for( ClientList::ConstIterator it = stacking.begin();
00660          it != stacking.end();
00661          ++it )
00662         kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer();
00663     kDebug() << "\n\n";
00664 #endif
00665     return stacking;
00666     }
00667 
00668 void Workspace::blockStackingUpdates( bool block )
00669     {
00670     if( block )
00671         {
00672         if( block_stacking_updates == 0 )
00673             blocked_propagating_new_clients = false;
00674         ++block_stacking_updates;
00675         }
00676     else // !block
00677         if( --block_stacking_updates == 0 )
00678             updateStackingOrder( blocked_propagating_new_clients );
00679     }
00680 
00681 // Ensure list is in stacking order
00682 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00683     {
00684 // TODO    Q_ASSERT( block_stacking_updates == 0 );
00685     if( list.count() < 2 )
00686         return list;
00687     // TODO is this worth optimizing?
00688     ClientList result = list;
00689     for( ClientList::ConstIterator it = stacking_order.begin();
00690          it != stacking_order.end();
00691          ++it )
00692         if( result.removeAll( *it ) != 0 )
00693             result.append( *it );
00694     return result;
00695     }
00696 
00697 // check whether a transient should be actually kept above its mainwindow
00698 // there may be some special cases where this rule shouldn't be enfored
00699 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00700     {
00701     // When topmenu's mainwindow becomes active, topmenu is raised and shown.
00702     // They also belong to the Dock layer. This makes them to be very high.
00703     // Therefore don't keep group transients above them, otherwise this would move
00704     // group transients way too high.
00705     if( mainwindow->isTopMenu() && transient->groupTransient())
00706         return false;
00707     // #93832 - don't keep splashscreens above dialogs
00708     if( transient->isSplash() && mainwindow->isDialog())
00709         return false;
00710     // This is rather a hack for #76026. Don't keep non-modal dialogs above
00711     // the mainwindow, but only if they're group transient (since only such dialogs
00712     // have taskbar entry in Kicker). A proper way of doing this (both kwin and kicker)
00713     // needs to be found.
00714     if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
00715         return false;
00716     // #63223 - don't keep transients above docks, because the dock is kept high,
00717     // and e.g. dialogs for them would be too high too
00718     if( mainwindow->isDock())
00719         return false;
00720     return true;
00721     }
00722 
00723 // Returns all windows in their stacking order on the root window, used only by compositing.
00724 // TODO This possibly should be optimized to avoid the X roundtrip and building it every pass.
00725 ToplevelList Workspace::compositingStackingOrder() const
00726     {
00727     Window dummy;
00728     Window* windows = NULL;
00729     unsigned int count = 0;
00730     XQueryTree( display(), rootWindow(), &dummy, &dummy, &windows, &count );
00731     ToplevelList ret;
00732     // use our own stacking order, not the X one, as they may differ
00733     foreach( Client* c, stacking_order )
00734         ret.append( c );
00735     for( unsigned int i = 0;
00736          i < count;
00737          ++i )
00738         {
00739         if( Unmanaged* c = findUnmanaged( WindowMatchPredicate( windows[ i ] )))
00740             ret.append( c );
00741         }
00742     foreach( Deleted* c, deleted )
00743         ret.append( c );
00744     if( windows != NULL )
00745         XFree( windows );
00746     return ret;
00747     }
00748 
00749 //*******************************
00750 // Client
00751 //*******************************
00752 
00753 void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event )
00754     {
00755     switch ( detail )
00756         {
00757         case Above:
00758         case TopIf:
00759             workspace()->raiseClientRequest( this, src, timestamp );
00760           break;
00761         case Below:
00762         case BottomIf:
00763             workspace()->lowerClientRequest( this, src, timestamp );
00764           break;
00765         case Opposite:
00766         default:
00767             break;
00768         }
00769     if( send_event )
00770         sendSyntheticConfigureNotify();
00771     }
00772     
00773 void Client::setKeepAbove( bool b )
00774     {
00775     b = rules()->checkKeepAbove( b );
00776     if( b && !rules()->checkKeepBelow( false ))
00777         setKeepBelow( false );
00778     if ( b == keepAbove())
00779         { // force hint change if different
00780         if( bool( info->state() & NET::KeepAbove ) != keepAbove())
00781             info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00782         return;
00783         }
00784     keep_above = b;
00785     info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00786     if( decoration != NULL )
00787         decoration->emitKeepAboveChanged( keepAbove());
00788     workspace()->updateClientLayer( this );
00789     updateWindowRules();
00790     }
00791 
00792 void Client::setKeepBelow( bool b )
00793     {
00794     b = rules()->checkKeepBelow( b );
00795     if( b && !rules()->checkKeepAbove( false ))
00796         setKeepAbove( false );
00797     if ( b == keepBelow())
00798         { // force hint change if different
00799         if( bool( info->state() & NET::KeepBelow ) != keepBelow())
00800             info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00801         return;
00802         }
00803     keep_below = b;
00804     info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00805     if( decoration != NULL )
00806         decoration->emitKeepBelowChanged( keepBelow());
00807     workspace()->updateClientLayer( this );
00808     updateWindowRules();
00809     }
00810 
00811 Layer Client::layer() const
00812     {
00813     if( in_layer == UnknownLayer )
00814         const_cast< Client* >( this )->in_layer = belongsToLayer();
00815     return in_layer;
00816     }
00817 
00818 Layer Client::belongsToLayer() const
00819     {
00820     if( isDesktop())
00821         return DesktopLayer;
00822     if( isSplash())         // no damn annoying splashscreens
00823         return NormalLayer; // getting in the way of everything else
00824     if( isDock() && keepBelow())
00825         // slight hack for the 'allow window to cover panel' Kicker setting
00826         // don't move keepbelow docks below normal window, but only to the same
00827         // layer, so that both may be raised to cover the other
00828         return NormalLayer;
00829     if( keepBelow())
00830         return BelowLayer;
00831     if( isDock() && !keepBelow())
00832         return DockLayer;
00833     if( isTopMenu())
00834         return DockLayer;
00835     // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order,
00836     // i.e. the window set to be topmost by the user (also includes transients of the fullscreen window)
00837     const Client* ac = workspace()->mostRecentlyActivatedClient(); // instead of activeClient() - avoids flicker
00838     const Client* top = workspace()->topClientOnDesktop( desktop(), true, false );
00839     if( isFullScreen() && ac != NULL && top != NULL
00840         && ( ac == this || this->group() == ac->group())
00841         && ( top == this || this->group() == top->group()))
00842         return ActiveLayer;
00843     if( keepAbove())
00844         return AboveLayer;
00845     return NormalLayer;
00846     }
00847 
00848 } // 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
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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