kwin Library API Documentation

layers.cpp

00001 /***************************************************************** 00002 KWin - the KDE window manager 00003 This file is part of the KDE project. 00004 00005 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org> 00006 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> 00007 00008 You can Freely distribute this program under the GNU General Public 00009 License. See the file "COPYING" for the exact licensing terms. 00010 ******************************************************************/ 00011 00012 // SELI zmenit doc 00013 00014 /* 00015 00016 This file contains things relevant to stacking order and layers. 00017 00018 Design: 00019 00020 Normal unconstrained stacking order, as requested by the user (by clicking 00021 on windows to raise them, etc.), is in Workspace::unconstrained_stacking_order. 00022 That list shouldn't be used at all, except for building 00023 Workspace::stacking_order. The building is done 00024 in Workspace::constrainedStackingOrder(). Only Workspace::stackingOrder() should 00025 be used to get the stacking order, because it also checks the stacking order 00026 is up to date. 00027 All clients are also stored in Workspace::clients (except for isDesktop() clients, 00028 as those are very special, and are stored in Workspace::desktops), in the order 00029 the clients were created. 00030 00031 Every window has one layer assigned in which it is. There are 6 layers, 00032 from bottom : DesktopLayer, BelowLayer, NormalLayer, 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 "popupinfo.h" 00074 #include "group.h" 00075 #include "rules.h" 00076 00077 extern Time qt_x_time; 00078 00079 namespace KWinInternal 00080 { 00081 00082 //******************************* 00083 // Workspace 00084 //******************************* 00085 00086 void Workspace::updateClientLayer( Client* c ) 00087 { 00088 if( c == NULL ) 00089 return; 00090 if( c->layer() == c->belongsToLayer()) 00091 return; 00092 StackingUpdatesBlocker blocker( this ); 00093 c->invalidateLayer(); // invalidate, will be updated when doing restacking 00094 for( ClientList::ConstIterator it = c->transients().begin(); 00095 it != c->transients().end(); 00096 ++it ) 00097 updateClientLayer( *it ); 00098 } 00099 00100 void Workspace::updateStackingOrder( bool propagate_new_clients ) 00101 { 00102 if( block_stacking_updates > 0 ) 00103 { 00104 blocked_propagating_new_clients |= propagate_new_clients; 00105 return; 00106 } 00107 ClientList new_stacking_order = constrainedStackingOrder(); 00108 bool changed = ( new_stacking_order != stacking_order ); 00109 stacking_order = new_stacking_order; 00110 #if 0 00111 kdDebug() << "stacking:" << changed << endl; 00112 if( changed || propagate_new_clients ) 00113 { 00114 for( ClientList::ConstIterator it = stacking_order.begin(); 00115 it != stacking_order.end(); 00116 ++it ) 00117 kdDebug() << (void*)(*it) << *it << endl; 00118 } 00119 #endif 00120 if( changed || propagate_new_clients ) 00121 propagateClients( propagate_new_clients ); 00122 } 00123 00128 void Workspace::propagateClients( bool propagate_new_clients ) 00129 { 00130 Window *cl; // MW we should not assume WId and Window to be compatible 00131 // when passig pointers around. 00132 00133 // restack the windows according to the stacking order 00134 Window* new_stack = new Window[ stacking_order.count() + 2 ]; 00135 int pos = 0; 00136 // Stack all windows under the support window. The support window is 00137 // not used for anything (besides the NETWM property), and it's not shown, 00138 // but it was lowered after kwin startup. Stacking all clients below 00139 // it ensures that no client will be ever shown above override-redirect 00140 // windows (e.g. popups). 00141 new_stack[ pos++ ] = supportWindow->winId(); 00142 int topmenu_space_pos = 1; // not 0, that's supportWindow !!! 00143 for( ClientList::ConstIterator it = stacking_order.fromLast(); 00144 it != stacking_order.end(); 00145 --it ) 00146 { 00147 new_stack[ pos++ ] = (*it)->frameId(); 00148 if( (*it)->belongsToLayer() >= DockLayer ) 00149 topmenu_space_pos = pos; 00150 } 00151 if( topmenu_space != NULL ) 00152 { // make sure the topmenu space is below all topmenus, fullscreens, etc. 00153 for( int i = pos; 00154 i > topmenu_space_pos; 00155 --i ) 00156 new_stack[ i ] = new_stack[ i - 1 ]; 00157 new_stack[ topmenu_space_pos ] = topmenu_space->winId(); 00158 ++pos; 00159 } 00160 // TODO isn't it too inefficient to restart always all clients? 00161 // TODO don't restack not visible windows? 00162 assert( new_stack[ 0 ] = supportWindow->winId()); 00163 XRestackWindows(qt_xdisplay(), new_stack, pos); 00164 delete [] new_stack; 00165 00166 if ( propagate_new_clients ) 00167 { 00168 cl = new Window[ desktops.count() + clients.count()]; 00169 pos = 0; 00170 // TODO this is still not completely in the map order 00171 for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it ) 00172 cl[pos++] = (*it)->window(); 00173 for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it ) 00174 cl[pos++] = (*it)->window(); 00175 rootInfo->setClientList( cl, pos ); 00176 delete [] cl; 00177 } 00178 00179 cl = new Window[ stacking_order.count()]; 00180 pos = 0; 00181 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) 00182 cl[pos++] = (*it)->window(); 00183 rootInfo->setClientListStacking( cl, pos ); 00184 delete [] cl; 00185 00186 #if 0 // not necessary anymore? 00187 if ( tab_box->isVisible() ) 00188 tab_box->raise(); 00189 00190 if ( popupinfo->isVisible() ) 00191 popupinfo->raise(); 00192 00193 raiseElectricBorders(); 00194 #endif 00195 } 00196 00197 00203 // TODO misleading name for this method 00204 Client* Workspace::topClientOnDesktop( int desktop, bool unconstrained ) const 00205 { 00206 // TODO Q_ASSERT( block_stacking_updates == 0 ); 00207 ClientList::ConstIterator begin, end; 00208 if( !unconstrained ) 00209 { 00210 begin = stacking_order.fromLast(); 00211 end = stacking_order.end(); 00212 } 00213 else 00214 { 00215 begin = unconstrained_stacking_order.fromLast(); 00216 end = unconstrained_stacking_order.end(); 00217 } 00218 for( ClientList::ConstIterator it = begin; 00219 it != end; 00220 --it ) 00221 { 00222 if ( (*it)->isOnDesktop( desktop ) && !(*it)->isSpecialWindow() 00223 && (*it)->isShown( false ) && (*it)->wantsTabFocus()) 00224 return *it; 00225 } 00226 return 0; 00227 } 00228 00229 Client* Workspace::findDesktop( bool topmost, int desktop ) const 00230 { 00231 // TODO Q_ASSERT( block_stacking_updates == 0 ); 00232 if( topmost ) 00233 { 00234 for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it) 00235 { 00236 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop() 00237 && (*it)->isShown( true )) 00238 return *it; 00239 } 00240 } 00241 else // bottom-most 00242 { 00243 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it) 00244 { 00245 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop() 00246 && (*it)->isShown( true )) 00247 return *it; 00248 } 00249 } 00250 return NULL; 00251 } 00252 00253 void Workspace::raiseOrLowerClient( Client *c) 00254 { 00255 if (!c) return; 00256 Client* topmost = NULL; 00257 // TODO Q_ASSERT( block_stacking_updates == 0 ); 00258 if ( most_recently_raised && stacking_order.contains( most_recently_raised ) && 00259 most_recently_raised->isShown( true ) && c->isOnCurrentDesktop()) 00260 topmost = most_recently_raised; 00261 else 00262 topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop()); 00263 00264 if( c == topmost) 00265 lowerClient(c); 00266 else 00267 raiseClient(c); 00268 } 00269 00270 00271 void Workspace::lowerClient( Client* c ) 00272 { 00273 if ( !c ) 00274 return; 00275 if( c->isTopMenu()) 00276 return; 00277 00278 c->cancelAutoRaise(); 00279 00280 StackingUpdatesBlocker blocker( this ); 00281 00282 unconstrained_stacking_order.remove( c ); 00283 unconstrained_stacking_order.prepend( c ); 00284 if( c->isTransient()) 00285 { 00286 // lower also mainclients, in their reversed stacking order 00287 ClientList mainclients = ensureStackingOrder( c->mainClients()); 00288 for( ClientList::ConstIterator it = mainclients.fromLast(); 00289 it != mainclients.end(); 00290 ++it ) 00291 lowerClient( *it ); 00292 } 00293 00294 if ( c == most_recently_raised ) 00295 most_recently_raised = 0; 00296 } 00297 00298 void Workspace::lowerClientWithinApplication( Client* c ) 00299 { 00300 if ( !c ) 00301 return; 00302 if( c->isTopMenu()) 00303 return; 00304 00305 c->cancelAutoRaise(); 00306 00307 StackingUpdatesBlocker blocker( this ); 00308 00309 unconstrained_stacking_order.remove( c ); 00310 bool lowered = false; 00311 // first try to put it below the bottom-most window of the application 00312 for( ClientList::Iterator it = unconstrained_stacking_order.begin(); 00313 it != unconstrained_stacking_order.end(); 00314 ++it ) 00315 if( Client::belongToSameApplication( *it, c )) 00316 { 00317 unconstrained_stacking_order.insert( it, c ); 00318 lowered = true; 00319 break; 00320 } 00321 if( !lowered ) 00322 unconstrained_stacking_order.prepend( c ); 00323 // ignore mainwindows 00324 } 00325 00326 void Workspace::raiseClient( Client* c ) 00327 { 00328 if ( !c ) 00329 return; 00330 if( c->isTopMenu()) 00331 return; 00332 00333 c->cancelAutoRaise(); 00334 00335 StackingUpdatesBlocker blocker( this ); 00336 00337 if( c->isTransient()) 00338 { 00339 ClientList mainclients = ensureStackingOrder( c->mainClients()); 00340 for( ClientList::ConstIterator it = mainclients.begin(); 00341 it != mainclients.end(); 00342 ++it ) 00343 raiseClient( *it ); 00344 } 00345 00346 unconstrained_stacking_order.remove( c ); 00347 unconstrained_stacking_order.append( c ); 00348 00349 if( !c->isSpecialWindow()) 00350 { 00351 most_recently_raised = c; 00352 pending_take_activity = NULL; 00353 } 00354 } 00355 00356 void Workspace::raiseClientWithinApplication( Client* c ) 00357 { 00358 if ( !c ) 00359 return; 00360 if( c->isTopMenu()) 00361 return; 00362 00363 c->cancelAutoRaise(); 00364 00365 StackingUpdatesBlocker blocker( this ); 00366 // ignore mainwindows 00367 00368 // first try to put it above the top-most window of the application 00369 for( ClientList::Iterator it = unconstrained_stacking_order.fromLast(); 00370 it != unconstrained_stacking_order.end(); 00371 --it ) 00372 { 00373 if( *it == c ) // don't lower it just because it asked to be raised 00374 return; 00375 if( Client::belongToSameApplication( *it, c )) 00376 { 00377 unconstrained_stacking_order.remove( c ); 00378 ++it; // insert after the found one 00379 unconstrained_stacking_order.insert( it, c ); 00380 return; 00381 } 00382 } 00383 } 00384 00385 void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp ) 00386 { 00387 if( src == NET::FromTool || allowFullClientRaising( c, timestamp )) 00388 raiseClient( c ); 00389 else 00390 { 00391 raiseClientWithinApplication( c ); 00392 c->demandAttention(); 00393 } 00394 } 00395 00396 void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time /*timestamp*/ ) 00397 { 00398 // If the client has support for all this focus stealing prevention stuff, 00399 // do only lowering within the application, as that's the more logical 00400 // variant of lowering when application requests it. 00401 // No demanding of attention here of course. 00402 if( src == NET::FromTool || !c->hasUserTimeSupport()) 00403 lowerClient( c ); 00404 else 00405 lowerClientWithinApplication( c ); 00406 } 00407 00408 void Workspace::restackClientUnderActive( Client* c ) 00409 { 00410 if( c->isTopMenu()) 00411 return; 00412 if( !active_client || active_client == c ) 00413 { 00414 raiseClient( c ); 00415 return; 00416 } 00417 00418 // put in the stacking order below _all_ windows belonging to the active application 00419 assert( unconstrained_stacking_order.contains( active_client )); 00420 for( ClientList::Iterator it = unconstrained_stacking_order.begin(); 00421 it != unconstrained_stacking_order.end(); 00422 ++it ) 00423 { // TODO ignore topmenus? 00424 if( Client::belongToSameApplication( active_client, *it )) 00425 { 00426 if( *it != c ) 00427 { 00428 unconstrained_stacking_order.remove( c ); 00429 unconstrained_stacking_order.insert( it, c ); 00430 } 00431 break; 00432 } 00433 } 00434 assert( unconstrained_stacking_order.contains( c )); 00435 if( c->wantsTabFocus() && focus_chain.contains( active_client )) 00436 { 00437 // also put in focus_chain after all windows belonging to the active application 00438 focus_chain.remove( c ); 00439 for( ClientList::Iterator it = focus_chain.fromLast(); 00440 it != focus_chain.end(); 00441 --it ) 00442 { 00443 if( Client::belongToSameApplication( active_client, *it )) 00444 { 00445 focus_chain.insert( it, c ); 00446 break; 00447 } 00448 } 00449 } 00450 updateStackingOrder(); 00451 } 00452 00453 void Workspace::circulateDesktopApplications() 00454 { 00455 if ( desktops.count() > 1 ) 00456 { 00457 bool change_active = activeClient()->isDesktop(); 00458 raiseClient( findDesktop( false, currentDesktop())); 00459 if( change_active ) // if the previously topmost Desktop was active, activate this new one 00460 activateClient( findDesktop( true, currentDesktop())); 00461 } 00462 // if there's no active client, make desktop the active one 00463 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 ) 00464 activateClient( findDesktop( true, currentDesktop())); 00465 } 00466 00467 00471 ClientList Workspace::constrainedStackingOrder() 00472 { 00473 ClientList layer[ NumLayers ]; 00474 00475 #if 0 00476 kdDebug() << "stacking1:" << endl; 00477 #endif 00478 // build the order from layers 00479 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin(); 00480 it != unconstrained_stacking_order.end(); 00481 ++it ) 00482 { 00483 #if 0 00484 kdDebug() << (void*)(*it) << *it << endl; 00485 #endif 00486 layer[ (*it)->layer() ].append( *it ); 00487 } 00488 ClientList stacking; 00489 for( Layer lay = FirstLayer; 00490 lay < NumLayers; 00491 ++lay ) 00492 stacking += layer[ lay ]; 00493 #if 0 00494 kdDebug() << "stacking2:" << endl; 00495 for( ClientList::ConstIterator it = stacking.begin(); 00496 it != stacking.end(); 00497 ++it ) 00498 kdDebug() << (void*)(*it) << *it << endl; 00499 #endif 00500 // now keep transients above their mainwindows 00501 // TODO this could(?) use some optimization 00502 for( ClientList::Iterator it = stacking.fromLast(); 00503 it != stacking.end(); 00504 ) 00505 { 00506 if( !(*it)->isTransient()) 00507 { 00508 --it; 00509 continue; 00510 } 00511 ClientList::Iterator it2 = stacking.end(); 00512 if( (*it)->groupTransient()) 00513 { 00514 if( (*it)->group()->members().count() > 0 ) 00515 { // find topmost client this one is transient for 00516 for( it2 = stacking.fromLast(); 00517 it2 != stacking.end(); 00518 --it2 ) 00519 { 00520 if( *it2 == *it ) 00521 { 00522 it2 = stacking.end(); // don't reorder 00523 break; 00524 } 00525 if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it )) 00526 break; 00527 } 00528 } // else it2 remains pointing at stacking.end() 00529 } 00530 else 00531 { 00532 for( it2 = stacking.fromLast(); 00533 it2 != stacking.end(); 00534 --it2 ) 00535 { 00536 if( *it2 == *it ) 00537 { 00538 it2 = stacking.end(); // don't reorder 00539 break; 00540 } 00541 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it )) 00542 break; 00543 } 00544 } 00545 // kdDebug() << "STACK:" << (*it) << ":" << ( it2 == stacking.end() ? ((Client*)0) : (*it2)) << endl; 00546 if( it2 == stacking.end()) 00547 { 00548 --it; 00549 continue; 00550 } 00551 Client* current = *it; 00552 ClientList::Iterator remove_it = it; 00553 --it; 00554 stacking.remove( remove_it ); 00555 if( !current->transients().isEmpty()) // this one now can be possibly above its transients, 00556 it = it2; // so go again higher in the stack order and possibly move those transients again 00557 ++it2; // insert after the mainwindow, it's ok if it2 is now stacking.end() 00558 stacking.insert( it2, current ); 00559 } 00560 #if 0 00561 kdDebug() << "stacking3:" << endl; 00562 for( ClientList::ConstIterator it = stacking.begin(); 00563 it != stacking.end(); 00564 ++it ) 00565 kdDebug() << (void*)(*it) << *it << endl; 00566 kdDebug() << "\n\n" << endl; 00567 #endif 00568 return stacking; 00569 } 00570 00571 void Workspace::blockStackingUpdates( bool block ) 00572 { 00573 if( block ) 00574 { 00575 if( block_stacking_updates == 0 ) 00576 blocked_propagating_new_clients = false; 00577 ++block_stacking_updates; 00578 } 00579 else // !block 00580 if( --block_stacking_updates == 0 ) 00581 updateStackingOrder( blocked_propagating_new_clients ); 00582 } 00583 00584 // Ensure list is in stacking order 00585 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const 00586 { 00587 // TODO Q_ASSERT( block_stacking_updates == 0 ); 00588 if( list.count() < 2 ) 00589 return list; 00590 // TODO is this worth optimizing? 00591 ClientList result = list; 00592 for( ClientList::ConstIterator it = stacking_order.begin(); 00593 it != stacking_order.end(); 00594 ++it ) 00595 if( result.remove( *it ) != 0 ) 00596 result.append( *it ); 00597 return result; 00598 } 00599 00600 // check whether a transient should be actually kept above its mainwindow 00601 // there may be some special cases where this rule shouldn't be enfored 00602 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient ) 00603 { 00604 // When topmenu's mainwindow becomes active, topmenu is raised and shown. 00605 // They also belong to the Dock layer. This makes them to be very high. 00606 // Therefore don't keep group transients above them, otherwise this would move 00607 // group transients way too high. 00608 if( mainwindow->isTopMenu() && transient->groupTransient()) 00609 return false; 00610 // This is rather a hack for #76026. Don't keep non-modal dialogs above 00611 // the mainwindow, but only if they're group transient (since only such dialogs 00612 // have taskbar entry in Kicker). A proper way of doing this (both kwin and kicker) 00613 // needs to be found. 00614 if( transient->isDialog() && !transient->isModal() && transient->groupTransient()) 00615 return false; 00616 return true; 00617 // #63223 - don't keep transients above docks, because the dock is kept high, 00618 // and e.g. dialogs for them would be too high too 00619 // TODO this doesn't really work - the transient should be raised after clicking 00620 // on the dock, but docks don't become active after clicking them 00621 if( mainwindow->isDock() && !mainwindow->keepBelow() 00622 && !mainwindow->isActive() && !transient->isActive()) // TODO !w->group()->isActive() ??? 00623 return false; 00624 return true; 00625 } 00626 00627 //******************************* 00628 // Client 00629 //******************************* 00630 00631 void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource src, Time timestamp, bool send_event ) 00632 { 00633 switch ( detail ) 00634 { 00635 case Above: 00636 case TopIf: 00637 workspace()->raiseClientRequest( this, src, timestamp ); 00638 break; 00639 case Below: 00640 case BottomIf: 00641 workspace()->lowerClientRequest( this, src, timestamp ); 00642 break; 00643 case Opposite: 00644 default: 00645 break; 00646 } 00647 if( send_event ) 00648 sendSyntheticConfigureNotify(); 00649 } 00650 00651 void Client::setKeepAbove( bool b ) 00652 { 00653 b = rules()->checkKeepAbove( b ); 00654 if( b ) 00655 setKeepBelow( false ); 00656 if ( b == keepAbove() 00657 || ( b && keepBelow())) // forced below 00658 { // force hint change if different 00659 if( bool( info->state() & NET::KeepAbove ) != keepAbove()) 00660 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove ); 00661 return; 00662 } 00663 keep_above = b; 00664 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove ); 00665 if( decoration != NULL ) 00666 decoration->emitKeepAboveChanged( keepAbove()); 00667 workspace()->updateClientLayer( this ); 00668 updateWindowRules(); 00669 } 00670 00671 void Client::setKeepBelow( bool b ) 00672 { 00673 b = rules()->checkKeepBelow( b ); 00674 if( b ) 00675 setKeepAbove( false ); 00676 if ( b == keepBelow() 00677 || ( b && keepAbove())) // forced above 00678 { // force hint change if different 00679 if( bool( info->state() & NET::KeepBelow ) != keepBelow()) 00680 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow ); 00681 return; 00682 } 00683 keep_below = b; 00684 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow ); 00685 if( decoration != NULL ) 00686 decoration->emitKeepBelowChanged( keepBelow()); 00687 workspace()->updateClientLayer( this ); 00688 updateWindowRules(); 00689 } 00690 00691 Layer Client::layer() const 00692 { 00693 if( in_layer == UnknownLayer ) 00694 const_cast< Client* >( this )->in_layer = belongsToLayer(); 00695 return in_layer; 00696 } 00697 00698 Layer Client::belongsToLayer() const 00699 { 00700 if( isDesktop()) 00701 return DesktopLayer; 00702 if( isSplash()) // no damn annoying splashscreens 00703 return NormalLayer; // getting in the way of everything else 00704 if( isDock() && keepBelow()) 00705 // slight hack for the 'allow window to cover panel' Kicker setting 00706 // don't move keepbelow docks below normal window, but only to the same 00707 // layer, so that both may be raised to cover the other 00708 return NormalLayer; 00709 if( keepBelow()) 00710 return BelowLayer; 00711 if( isDock() && !keepBelow()) 00712 return DockLayer; 00713 if( isTopMenu()) 00714 return DockLayer; 00715 // only raise fullscreen above docks if it's the topmost window in unconstrained stacking order, 00716 // i.e. the window set to be topmost by the user 00717 bool raise_special_active_windows = ( workspace()->topClientOnDesktop( desktop(), true ) == this ); 00718 if( keepAbove()) 00719 return AboveLayer; 00720 if( isFullScreen() && workspace()->activeClient() != NULL 00721 && ( workspace()->activeClient() == this || this->hasTransient( workspace()->activeClient(), true )) 00722 && raise_special_active_windows ) 00723 return ActiveLayer; 00724 return NormalLayer; 00725 } 00726 00727 } // namespace
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 13 21:47:05 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003