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

twin

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

twin

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

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.7.1
This website is maintained by Timothy Pearson.