layers.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 #include <assert.h>
00066
00067 #include "utils.h"
00068 #include "client.h"
00069 #include "workspace.h"
00070 #include "tabbox.h"
00071 #include "popupinfo.h"
00072 #include "group.h"
00073 #include <kdebug.h>
00074
00075 namespace KWinInternal
00076 {
00077
00078
00079
00080
00081
00082 void Workspace::updateClientLayer( Client* c )
00083 {
00084 if( c == NULL )
00085 return;
00086 if( c->layer() == c->belongsToLayer())
00087 return;
00088 StackingUpdatesBlocker blocker( this );
00089 c->invalidateLayer();
00090 for( ClientList::ConstIterator it = c->transients().begin();
00091 it != c->transients().end();
00092 ++it )
00093 updateClientLayer( *it );
00094 }
00095
00096 void Workspace::updateStackingOrder( bool propagate_new_clients )
00097 {
00098 if( block_stacking_updates > 0 )
00099 {
00100 blocked_propagating_new_clients |= propagate_new_clients;
00101 return;
00102 }
00103 ClientList new_stacking_order = constrainedStackingOrder();
00104 bool changed = ( new_stacking_order != stacking_order );
00105 stacking_order = new_stacking_order;
00106 #if 0
00107 kdDebug() << "stacking:" << changed << endl;
00108 if( changed || propagate_new_clients )
00109 {
00110 for( ClientList::ConstIterator it = stacking_order.begin();
00111 it != stacking_order.end();
00112 ++it )
00113 kdDebug() << (void*)(*it) << *it << endl;
00114 }
00115 #endif
00116 if( changed || propagate_new_clients )
00117 propagateClients( propagate_new_clients );
00118 }
00119
00124 void Workspace::propagateClients( bool propagate_new_clients )
00125 {
00126 Window *cl;
00127
00128
00129
00130 Window* new_stack = new Window[ stacking_order.count() + 2 ];
00131 int pos = 0;
00132
00133
00134
00135
00136
00137 new_stack[ pos++ ] = supportWindow->winId();
00138 int topmenu_space_pos = 1;
00139 for( ClientList::ConstIterator it = stacking_order.fromLast();
00140 it != stacking_order.end();
00141 --it )
00142 {
00143 new_stack[ pos++ ] = (*it)->frameId();
00144 if( (*it)->isTopMenu())
00145 topmenu_space_pos = pos;
00146 }
00147 if( topmenu_space != NULL )
00148 {
00149 for( int i = pos;
00150 i > topmenu_space_pos;
00151 --i )
00152 new_stack[ i ] = new_stack[ i - 1 ];
00153 new_stack[ topmenu_space_pos ] = topmenu_space->winId();
00154 ++pos;
00155 }
00156
00157
00158 assert( new_stack[ 0 ] = supportWindow->winId());
00159 XRestackWindows(qt_xdisplay(), new_stack, pos);
00160 delete [] new_stack;
00161
00162 if ( propagate_new_clients )
00163 {
00164 cl = new Window[ desktops.count() + clients.count()];
00165 pos = 0;
00166
00167 for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it )
00168 cl[pos++] = (*it)->window();
00169 for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it )
00170 cl[pos++] = (*it)->window();
00171 rootInfo->setClientList( cl, pos );
00172 delete [] cl;
00173 }
00174
00175 cl = new Window[ stacking_order.count()];
00176 pos = 0;
00177 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
00178 cl[pos++] = (*it)->window();
00179 rootInfo->setClientListStacking( cl, pos );
00180 delete [] cl;
00181
00182 #if 0 // not necessary anymore?
00183 if ( tab_box->isVisible() )
00184 tab_box->raise();
00185
00186 if ( popupinfo->isVisible() )
00187 popupinfo->raise();
00188
00189 raiseElectricBorders();
00190 #endif
00191 }
00192
00193
00199
00200 Client* Workspace::topClientOnDesktop( int desktop, bool unconstrained ) const
00201 {
00202
00203 ClientList::ConstIterator begin, end;
00204 if( !unconstrained )
00205 {
00206 begin = stacking_order.fromLast();
00207 end = stacking_order.end();
00208 }
00209 else
00210 {
00211 begin = unconstrained_stacking_order.fromLast();
00212 end = unconstrained_stacking_order.end();
00213 }
00214 for( ClientList::ConstIterator it = begin;
00215 it != end;
00216 --it )
00217 {
00218 if ( (*it)->isOnDesktop( desktop ) && !(*it)->isSpecialWindow()
00219 && (*it)->isShown( false ) && (*it)->wantsTabFocus())
00220 return *it;
00221 }
00222 return 0;
00223 }
00224
00225 Client* Workspace::findDesktop( bool topmost, int desktop ) const
00226 {
00227
00228 if( topmost )
00229 {
00230 for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
00231 {
00232 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
00233 && (*it)->isShown( true ))
00234 return *it;
00235 }
00236 }
00237 else
00238 {
00239 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
00240 {
00241 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
00242 && (*it)->isShown( true ))
00243 return *it;
00244 }
00245 }
00246 return NULL;
00247 }
00248
00249 void Workspace::raiseOrLowerClient( Client *c)
00250 {
00251 if (!c) return;
00252 Client* topmost = NULL;
00253
00254 if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
00255 most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
00256 topmost = most_recently_raised;
00257 else
00258 topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
00259
00260 if( c == topmost)
00261 lowerClient(c);
00262 else
00263 raiseClient(c);
00264 }
00265
00266
00267 void Workspace::lowerClient( Client* c )
00268 {
00269 if ( !c )
00270 return;
00271
00272 c->cancelAutoRaise();
00273
00274 StackingUpdatesBlocker blocker( this );
00275
00276 unconstrained_stacking_order.remove( c );
00277 unconstrained_stacking_order.prepend( c );
00278 if( c->isTransient())
00279 {
00280
00281 ClientList mainclients = ensureStackingOrder( c->mainClients());
00282 for( ClientList::ConstIterator it = mainclients.fromLast();
00283 it != mainclients.end();
00284 ++it )
00285 lowerClient( *it );
00286 }
00287
00288 if ( c == most_recently_raised )
00289 most_recently_raised = 0;
00290 }
00291
00292 void Workspace::lowerClientWithinApplication( Client* c )
00293 {
00294 if ( !c )
00295 return;
00296
00297 c->cancelAutoRaise();
00298
00299 StackingUpdatesBlocker blocker( this );
00300
00301 unconstrained_stacking_order.remove( c );
00302 bool lowered = false;
00303
00304 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00305 it != unconstrained_stacking_order.end();
00306 ++it )
00307 if( Client::belongToSameApplication( *it, c ))
00308 {
00309 unconstrained_stacking_order.insert( it, c );
00310 lowered = true;
00311 break;
00312 }
00313 if( !lowered )
00314 unconstrained_stacking_order.prepend( c );
00315
00316 }
00317
00318 void Workspace::raiseClient( Client* c )
00319 {
00320 if ( !c )
00321 return;
00322
00323 c->cancelAutoRaise();
00324
00325 StackingUpdatesBlocker blocker( this );
00326
00327 if( c->isTransient())
00328 {
00329 ClientList mainclients = ensureStackingOrder( c->mainClients());
00330 for( ClientList::ConstIterator it = mainclients.begin();
00331 it != mainclients.end();
00332 ++it )
00333 raiseClient( *it );
00334 }
00335
00336 unconstrained_stacking_order.remove( c );
00337 unconstrained_stacking_order.append( c );
00338
00339 if( !c->isSpecialWindow())
00340 most_recently_raised = c;
00341 }
00342
00343 void Workspace::raiseClientWithinApplication( Client* c )
00344 {
00345 if ( !c )
00346 return;
00347
00348 c->cancelAutoRaise();
00349
00350 StackingUpdatesBlocker blocker( this );
00351
00352
00353
00354 for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
00355 it != unconstrained_stacking_order.end();
00356 --it )
00357 {
00358 if( *it == c )
00359 return;
00360 if( Client::belongToSameApplication( *it, c ))
00361 {
00362 unconstrained_stacking_order.remove( c );
00363 ++it;
00364 unconstrained_stacking_order.insert( it, c );
00365 return;
00366 }
00367 }
00368 restackClientUnderActive( c );
00369 }
00370
00371 void Workspace::raiseClientRequest( Client* c )
00372 {
00373 if( allowFullClientRaising( c ))
00374 raiseClient( c );
00375 else
00376 {
00377 raiseClientWithinApplication( c );
00378 c->demandAttention();
00379 }
00380 }
00381
00382 void Workspace::lowerClientRequest( Client* c )
00383 {
00384
00385
00386
00387
00388 if( c->hasUserTimeSupport())
00389 lowerClientWithinApplication( c );
00390 else
00391 lowerClient( c );
00392 }
00393
00394 void Workspace::restackClientUnderActive( Client* c )
00395 {
00396 if( !active_client || active_client == c )
00397 {
00398 raiseClient( c );
00399 return;
00400 }
00401
00402
00403 assert( unconstrained_stacking_order.contains( active_client ));
00404 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00405 it != unconstrained_stacking_order.end();
00406 ++it )
00407 {
00408 if( Client::belongToSameApplication( active_client, *it ))
00409 {
00410 if( *it != c )
00411 {
00412 unconstrained_stacking_order.remove( c );
00413 unconstrained_stacking_order.insert( it, c );
00414 }
00415 break;
00416 }
00417 }
00418 assert( unconstrained_stacking_order.contains( c ));
00419 if( c->wantsTabFocus() && focus_chain.contains( active_client ))
00420 {
00421
00422 focus_chain.remove( c );
00423 for( ClientList::Iterator it = focus_chain.fromLast();
00424 it != focus_chain.end();
00425 --it )
00426 {
00427 if( Client::belongToSameApplication( active_client, *it ))
00428 {
00429 focus_chain.insert( it, c );
00430 break;
00431 }
00432 }
00433 }
00434 updateStackingOrder();
00435 }
00436
00437 void Workspace::circulateDesktopApplications()
00438 {
00439 if ( desktops.count() > 1 )
00440 {
00441 bool change_active = activeClient()->isDesktop();
00442 raiseClient( findDesktop( false, currentDesktop()));
00443 if( change_active )
00444 activateClient( findDesktop( true, currentDesktop()));
00445 }
00446
00447 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00448 activateClient( findDesktop( true, currentDesktop()));
00449 }
00450
00451
00455 ClientList Workspace::constrainedStackingOrder()
00456 {
00457 ClientList layer[ NumLayers ];
00458
00459 #if 0
00460 kdDebug() << "stacking1:" << endl;
00461 #endif
00462
00463 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00464 it != unconstrained_stacking_order.end();
00465 ++it )
00466 {
00467 #if 0
00468 kdDebug() << (void*)(*it) << *it << endl;
00469 #endif
00470 layer[ (*it)->layer() ].append( *it );
00471 }
00472 ClientList stacking;
00473 for( Layer lay = FirstLayer;
00474 lay < NumLayers;
00475 ++lay )
00476 stacking += layer[ lay ];
00477 #if 0
00478 kdDebug() << "stacking2:" << endl;
00479 for( ClientList::ConstIterator it = stacking.begin();
00480 it != stacking.end();
00481 ++it )
00482 kdDebug() << (void*)(*it) << *it << endl;
00483 #endif
00484
00485
00486 for( ClientList::Iterator it = stacking.fromLast();
00487 it != stacking.end();
00488 )
00489 {
00490 if( !(*it)->isTransient())
00491 {
00492 --it;
00493 continue;
00494 }
00495 ClientList::Iterator it2 = stacking.end();
00496 if( (*it)->groupTransient())
00497 {
00498 if( (*it)->group()->members().count() > 0 )
00499 {
00500 for( it2 = stacking.fromLast();
00501 it2 != stacking.end();
00502 --it2 )
00503 {
00504 if( *it2 == *it )
00505 {
00506 it2 = stacking.end();
00507 break;
00508 }
00509 if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
00510 break;
00511 }
00512 }
00513 }
00514 else
00515 {
00516 for( it2 = stacking.fromLast();
00517 it2 != stacking.end();
00518 --it2 )
00519 {
00520 if( *it2 == *it )
00521 {
00522 it2 = stacking.end();
00523 break;
00524 }
00525 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00526 break;
00527 }
00528 }
00529
00530 if( it2 == stacking.end())
00531 {
00532 --it;
00533 continue;
00534 }
00535 Client* current = *it;
00536 ClientList::Iterator remove_it = it;
00537 --it;
00538 stacking.remove( remove_it );
00539 if( !current->transients().isEmpty())
00540 it = it2;
00541 ++it2;
00542 stacking.insert( it2, current );
00543 }
00544 #if 0
00545 kdDebug() << "stacking3:" << endl;
00546 for( ClientList::ConstIterator it = stacking.begin();
00547 it != stacking.end();
00548 ++it )
00549 kdDebug() << (void*)(*it) << *it << endl;
00550 kdDebug() << "\n\n" << endl;
00551 #endif
00552 return stacking;
00553 }
00554
00555 void Workspace::blockStackingUpdates( bool block )
00556 {
00557 if( block )
00558 {
00559 if( block_stacking_updates == 0 )
00560 blocked_propagating_new_clients = false;
00561 ++block_stacking_updates;
00562 }
00563 else
00564 if( --block_stacking_updates == 0 )
00565 updateStackingOrder( blocked_propagating_new_clients );
00566 }
00567
00568
00569 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00570 {
00571
00572 if( list.count() < 2 )
00573 return list;
00574
00575 ClientList result = list;
00576 for( ClientList::ConstIterator it = stacking_order.begin();
00577 it != stacking_order.end();
00578 ++it )
00579 if( result.remove( *it ) != 0 )
00580 result.append( *it );
00581 return result;
00582 }
00583
00584
00585
00586 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00587 {
00588
00589
00590
00591
00592 if( mainwindow->isTopMenu() && transient->groupTransient())
00593 return false;
00594 return true;
00595
00596
00597
00598
00599 if( mainwindow->isDock() && !mainwindow->keepBelow()
00600 && !mainwindow->isActive() && !transient->isActive())
00601 return false;
00602 return true;
00603 }
00604
00605
00606
00607
00608
00609 void Client::restackWindow( Window , int detail, NET::RequestSource source, bool send_event )
00610 {
00611 switch ( detail )
00612 {
00613 case Above:
00614 case TopIf:
00615 if( source == NET::FromTool )
00616 workspace()->raiseClient( this );
00617 else
00618 workspace()->raiseClientRequest( this );
00619 break;
00620 case Below:
00621 case BottomIf:
00622 if( source == NET::FromTool )
00623 workspace()->lowerClient( this );
00624 else
00625 workspace()->lowerClientRequest( this );
00626 break;
00627 case Opposite:
00628 default:
00629 break;
00630 }
00631 if( send_event )
00632 sendSyntheticConfigureNotify();
00633 }
00634
00635 void Client::setKeepAbove( bool b )
00636 {
00637 if ( b == keepAbove() )
00638 return;
00639 setKeepBelow( false );
00640 keep_above = b;
00641 info->setState( b ? NET::KeepAbove : 0, NET::KeepAbove );
00642
00643 workspace()->updateClientLayer( this );
00644 }
00645
00646 void Client::setKeepBelow( bool b )
00647 {
00648 if ( b == keepBelow() )
00649 return;
00650 setKeepAbove( false );
00651 keep_below = b;
00652 info->setState( b ? NET::KeepBelow : 0, NET::KeepBelow );
00653 workspace()->updateClientLayer( this );
00654 }
00655
00656 Layer Client::layer() const
00657 {
00658 if( in_layer == UnknownLayer )
00659 const_cast< Client* >( this )->in_layer = belongsToLayer();
00660 return in_layer;
00661 }
00662
00663 Layer Client::belongsToLayer() const
00664 {
00665 if( isDesktop())
00666 return DesktopLayer;
00667 if( isSplash())
00668 return NormalLayer;
00669 if( isDock() && keepBelow())
00670
00671
00672
00673 return NormalLayer;
00674 if( keepBelow())
00675 return BelowLayer;
00676 if( isDock() && !keepBelow())
00677 return DockLayer;
00678 if( isTopMenu())
00679 return DockLayer;
00680
00681
00682 bool raise_special_active_windows = ( workspace()->topClientOnDesktop( desktop(), true ) == this );
00683 if( keepAbove())
00684 return AboveLayer;
00685 if( isFullScreen() && workspace()->activeClient() != NULL
00686 && ( workspace()->activeClient() == this || this->hasTransient( workspace()->activeClient(), true ))
00687 && raise_special_active_windows )
00688 return ActiveLayer;
00689 return NormalLayer;
00690 }
00691
00692 }
This file is part of the documentation for kwin Library Version 3.2.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Mar 5 04:41:14 2004 by
doxygen 1.3.6-20040222 written by
Dimitri van Heesch, © 1997-2003