• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kwin
 

kwin

layers.cpp

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

kwin

Skip menu "kwin"
  • Main Page
  • Alphabetical List
  • Class List
  • File List
  • Class Members

kwin

Skip menu "kwin"
  • kate
  • kwin
  •   lib
  • libkonq
Generated for kwin by doxygen 1.5.6
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |