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 }
00369
00370 void Workspace::raiseClientRequest( Client* c )
00371 {
00372 if( allowFullClientRaising( c ))
00373 raiseClient( c );
00374 else
00375 {
00376 raiseClientWithinApplication( c );
00377 c->demandAttention();
00378 }
00379 }
00380
00381 void Workspace::lowerClientRequest( Client* c )
00382 {
00383
00384
00385
00386
00387 if( c->hasUserTimeSupport())
00388 lowerClientWithinApplication( c );
00389 else
00390 lowerClient( c );
00391 }
00392
00393 void Workspace::restackClientUnderActive( Client* c )
00394 {
00395 if( !active_client || active_client == c )
00396 {
00397 raiseClient( c );
00398 return;
00399 }
00400
00401
00402 assert( unconstrained_stacking_order.contains( active_client ));
00403 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00404 it != unconstrained_stacking_order.end();
00405 ++it )
00406 {
00407 if( Client::belongToSameApplication( active_client, *it ))
00408 {
00409 if( *it != c )
00410 {
00411 unconstrained_stacking_order.remove( c );
00412 unconstrained_stacking_order.insert( it, c );
00413 }
00414 break;
00415 }
00416 }
00417 assert( unconstrained_stacking_order.contains( c ));
00418 if( c->wantsTabFocus() && focus_chain.contains( active_client ))
00419 {
00420
00421 focus_chain.remove( c );
00422 for( ClientList::Iterator it = focus_chain.fromLast();
00423 it != focus_chain.end();
00424 --it )
00425 {
00426 if( Client::belongToSameApplication( active_client, *it ))
00427 {
00428 focus_chain.insert( it, c );
00429 break;
00430 }
00431 }
00432 }
00433 updateStackingOrder();
00434 }
00435
00436 void Workspace::circulateDesktopApplications()
00437 {
00438 if ( desktops.count() > 1 )
00439 {
00440 bool change_active = activeClient()->isDesktop();
00441 raiseClient( findDesktop( false, currentDesktop()));
00442 if( change_active )
00443 activateClient( findDesktop( true, currentDesktop()));
00444 }
00445
00446 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00447 activateClient( findDesktop( true, currentDesktop()));
00448 }
00449
00450
00454 ClientList Workspace::constrainedStackingOrder()
00455 {
00456 ClientList layer[ NumLayers ];
00457
00458 #if 0
00459 kdDebug() << "stacking1:" << endl;
00460 #endif
00461
00462 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00463 it != unconstrained_stacking_order.end();
00464 ++it )
00465 {
00466 #if 0
00467 kdDebug() << (void*)(*it) << *it << endl;
00468 #endif
00469 layer[ (*it)->layer() ].append( *it );
00470 }
00471 ClientList stacking;
00472 for( Layer lay = FirstLayer;
00473 lay < NumLayers;
00474 ++lay )
00475 stacking += layer[ lay ];
00476 #if 0
00477 kdDebug() << "stacking2:" << endl;
00478 for( ClientList::ConstIterator it = stacking.begin();
00479 it != stacking.end();
00480 ++it )
00481 kdDebug() << (void*)(*it) << *it << endl;
00482 #endif
00483
00484
00485 for( ClientList::Iterator it = stacking.fromLast();
00486 it != stacking.end();
00487 )
00488 {
00489 if( !(*it)->isTransient())
00490 {
00491 --it;
00492 continue;
00493 }
00494 ClientList::Iterator it2 = stacking.end();
00495 if( (*it)->groupTransient())
00496 {
00497 if( (*it)->group()->members().count() > 0 )
00498 {
00499 for( it2 = stacking.fromLast();
00500 it2 != stacking.end();
00501 --it2 )
00502 {
00503 if( *it2 == *it )
00504 {
00505 it2 = stacking.end();
00506 break;
00507 }
00508 if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
00509 break;
00510 }
00511 }
00512 }
00513 else
00514 {
00515 for( it2 = stacking.fromLast();
00516 it2 != stacking.end();
00517 --it2 )
00518 {
00519 if( *it2 == *it )
00520 {
00521 it2 = stacking.end();
00522 break;
00523 }
00524 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00525 break;
00526 }
00527 }
00528
00529 if( it2 == stacking.end())
00530 {
00531 --it;
00532 continue;
00533 }
00534 Client* current = *it;
00535 ClientList::Iterator remove_it = it;
00536 --it;
00537 stacking.remove( remove_it );
00538 if( !current->transients().isEmpty())
00539 it = it2;
00540 ++it2;
00541 stacking.insert( it2, current );
00542 }
00543 #if 0
00544 kdDebug() << "stacking3:" << endl;
00545 for( ClientList::ConstIterator it = stacking.begin();
00546 it != stacking.end();
00547 ++it )
00548 kdDebug() << (void*)(*it) << *it << endl;
00549 kdDebug() << "\n\n" << endl;
00550 #endif
00551 return stacking;
00552 }
00553
00554 void Workspace::blockStackingUpdates( bool block )
00555 {
00556 if( block )
00557 {
00558 if( block_stacking_updates == 0 )
00559 blocked_propagating_new_clients = false;
00560 ++block_stacking_updates;
00561 }
00562 else
00563 if( --block_stacking_updates == 0 )
00564 updateStackingOrder( blocked_propagating_new_clients );
00565 }
00566
00567
00568 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00569 {
00570
00571 if( list.count() < 2 )
00572 return list;
00573
00574 ClientList result = list;
00575 for( ClientList::ConstIterator it = stacking_order.begin();
00576 it != stacking_order.end();
00577 ++it )
00578 if( result.remove( *it ) != 0 )
00579 result.append( *it );
00580 return result;
00581 }
00582
00583
00584
00585 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00586 {
00587
00588
00589
00590
00591 if( mainwindow->isTopMenu() && transient->groupTransient())
00592 return false;
00593 return true;
00594
00595
00596
00597
00598 if( mainwindow->isDock() && !mainwindow->keepBelow()
00599 && !mainwindow->isActive() && !transient->isActive())
00600 return false;
00601 return true;
00602 }
00603
00604
00605
00606
00607
00608 void Client::restackWindow( Window , int detail, NET::RequestSource source, bool send_event )
00609 {
00610 switch ( detail )
00611 {
00612 case Above:
00613 case TopIf:
00614 if( source == NET::FromTool )
00615 workspace()->raiseClient( this );
00616 else
00617 workspace()->raiseClientRequest( this );
00618 break;
00619 case Below:
00620 case BottomIf:
00621 if( source == NET::FromTool )
00622 workspace()->lowerClient( this );
00623 else
00624 workspace()->lowerClientRequest( this );
00625 break;
00626 case Opposite:
00627 default:
00628 break;
00629 }
00630 if( send_event )
00631 sendSyntheticConfigureNotify();
00632 }
00633
00634 void Client::setKeepAbove( bool b )
00635 {
00636 if ( b == keepAbove() )
00637 return;
00638 setKeepBelow( false );
00639 keep_above = b;
00640 info->setState( b ? NET::KeepAbove : 0, NET::KeepAbove );
00641
00642 workspace()->updateClientLayer( this );
00643 }
00644
00645 void Client::setKeepBelow( bool b )
00646 {
00647 if ( b == keepBelow() )
00648 return;
00649 setKeepAbove( false );
00650 keep_below = b;
00651 info->setState( b ? NET::KeepBelow : 0, NET::KeepBelow );
00652 workspace()->updateClientLayer( this );
00653 }
00654
00655 Layer Client::layer() const
00656 {
00657 if( in_layer == UnknownLayer )
00658 const_cast< Client* >( this )->in_layer = belongsToLayer();
00659 return in_layer;
00660 }
00661
00662 Layer Client::belongsToLayer() const
00663 {
00664 if( isDesktop())
00665 return DesktopLayer;
00666 if( isSplash())
00667 return NormalLayer;
00668 if( isDock() && keepBelow())
00669
00670
00671
00672 return NormalLayer;
00673 if( keepBelow())
00674 return BelowLayer;
00675 if( isDock() && !keepBelow())
00676 return DockLayer;
00677 if( isTopMenu())
00678 return DockLayer;
00679
00680
00681 bool raise_special_active_windows = ( workspace()->topClientOnDesktop( desktop(), true ) == this );
00682 if( keepAbove())
00683 return AboveLayer;
00684 if( isFullScreen() && workspace()->activeClient() != NULL
00685 && ( workspace()->activeClient() == this || this->hasTransient( workspace()->activeClient(), true ))
00686 && raise_special_active_windows )
00687 return ActiveLayer;
00688 return NormalLayer;
00689 }
00690
00691 }
This file is part of the documentation for kwin Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Apr 11 13:44:53 2004 by
doxygen 1.3.6-20040222 written by
Dimitri van Heesch, © 1997-2003