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 if( c->isTopMenu())
00272 return;
00273
00274 c->cancelAutoRaise();
00275
00276 StackingUpdatesBlocker blocker( this );
00277
00278 unconstrained_stacking_order.remove( c );
00279 unconstrained_stacking_order.prepend( c );
00280 if( c->isTransient())
00281 {
00282
00283 ClientList mainclients = ensureStackingOrder( c->mainClients());
00284 for( ClientList::ConstIterator it = mainclients.fromLast();
00285 it != mainclients.end();
00286 ++it )
00287 lowerClient( *it );
00288 }
00289
00290 if ( c == most_recently_raised )
00291 most_recently_raised = 0;
00292 }
00293
00294 void Workspace::lowerClientWithinApplication( Client* c )
00295 {
00296 if ( !c )
00297 return;
00298 if( c->isTopMenu())
00299 return;
00300
00301 c->cancelAutoRaise();
00302
00303 StackingUpdatesBlocker blocker( this );
00304
00305 unconstrained_stacking_order.remove( c );
00306 bool lowered = false;
00307
00308 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00309 it != unconstrained_stacking_order.end();
00310 ++it )
00311 if( Client::belongToSameApplication( *it, c ))
00312 {
00313 unconstrained_stacking_order.insert( it, c );
00314 lowered = true;
00315 break;
00316 }
00317 if( !lowered )
00318 unconstrained_stacking_order.prepend( c );
00319
00320 }
00321
00322 void Workspace::raiseClient( 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 if( c->isTransient())
00334 {
00335 ClientList mainclients = ensureStackingOrder( c->mainClients());
00336 for( ClientList::ConstIterator it = mainclients.begin();
00337 it != mainclients.end();
00338 ++it )
00339 raiseClient( *it );
00340 }
00341
00342 unconstrained_stacking_order.remove( c );
00343 unconstrained_stacking_order.append( c );
00344
00345 if( !c->isSpecialWindow())
00346 most_recently_raised = c;
00347 }
00348
00349 void Workspace::raiseClientWithinApplication( 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
00361
00362 for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
00363 it != unconstrained_stacking_order.end();
00364 --it )
00365 {
00366 if( *it == c )
00367 return;
00368 if( Client::belongToSameApplication( *it, c ))
00369 {
00370 unconstrained_stacking_order.remove( c );
00371 ++it;
00372 unconstrained_stacking_order.insert( it, c );
00373 return;
00374 }
00375 }
00376 }
00377
00378 void Workspace::raiseClientRequest( Client* c )
00379 {
00380 if( allowFullClientRaising( c ))
00381 raiseClient( c );
00382 else
00383 {
00384 raiseClientWithinApplication( c );
00385 c->demandAttention();
00386 }
00387 }
00388
00389 void Workspace::lowerClientRequest( Client* c )
00390 {
00391
00392
00393
00394
00395 if( c->hasUserTimeSupport())
00396 lowerClientWithinApplication( c );
00397 else
00398 lowerClient( c );
00399 }
00400
00401 void Workspace::restackClientUnderActive( Client* c )
00402 {
00403 if( c->isTopMenu())
00404 return;
00405 if( !active_client || active_client == c )
00406 {
00407 raiseClient( c );
00408 return;
00409 }
00410
00411
00412 assert( unconstrained_stacking_order.contains( active_client ));
00413 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00414 it != unconstrained_stacking_order.end();
00415 ++it )
00416 {
00417 if( Client::belongToSameApplication( active_client, *it ))
00418 {
00419 if( *it != c )
00420 {
00421 unconstrained_stacking_order.remove( c );
00422 unconstrained_stacking_order.insert( it, c );
00423 }
00424 break;
00425 }
00426 }
00427 assert( unconstrained_stacking_order.contains( c ));
00428 if( c->wantsTabFocus() && focus_chain.contains( active_client ))
00429 {
00430
00431 focus_chain.remove( c );
00432 for( ClientList::Iterator it = focus_chain.fromLast();
00433 it != focus_chain.end();
00434 --it )
00435 {
00436 if( Client::belongToSameApplication( active_client, *it ))
00437 {
00438 focus_chain.insert( it, c );
00439 break;
00440 }
00441 }
00442 }
00443 updateStackingOrder();
00444 }
00445
00446 void Workspace::circulateDesktopApplications()
00447 {
00448 if ( desktops.count() > 1 )
00449 {
00450 bool change_active = activeClient()->isDesktop();
00451 raiseClient( findDesktop( false, currentDesktop()));
00452 if( change_active )
00453 activateClient( findDesktop( true, currentDesktop()));
00454 }
00455
00456 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00457 activateClient( findDesktop( true, currentDesktop()));
00458 }
00459
00460
00464 ClientList Workspace::constrainedStackingOrder()
00465 {
00466 ClientList layer[ NumLayers ];
00467
00468 #if 0
00469 kdDebug() << "stacking1:" << endl;
00470 #endif
00471
00472 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00473 it != unconstrained_stacking_order.end();
00474 ++it )
00475 {
00476 #if 0
00477 kdDebug() << (void*)(*it) << *it << endl;
00478 #endif
00479 layer[ (*it)->layer() ].append( *it );
00480 }
00481 ClientList stacking;
00482 for( Layer lay = FirstLayer;
00483 lay < NumLayers;
00484 ++lay )
00485 stacking += layer[ lay ];
00486 #if 0
00487 kdDebug() << "stacking2:" << endl;
00488 for( ClientList::ConstIterator it = stacking.begin();
00489 it != stacking.end();
00490 ++it )
00491 kdDebug() << (void*)(*it) << *it << endl;
00492 #endif
00493
00494
00495 for( ClientList::Iterator it = stacking.fromLast();
00496 it != stacking.end();
00497 )
00498 {
00499 if( !(*it)->isTransient())
00500 {
00501 --it;
00502 continue;
00503 }
00504 ClientList::Iterator it2 = stacking.end();
00505 if( (*it)->groupTransient())
00506 {
00507 if( (*it)->group()->members().count() > 0 )
00508 {
00509 for( it2 = stacking.fromLast();
00510 it2 != stacking.end();
00511 --it2 )
00512 {
00513 if( *it2 == *it )
00514 {
00515 it2 = stacking.end();
00516 break;
00517 }
00518 if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
00519 break;
00520 }
00521 }
00522 }
00523 else
00524 {
00525 for( it2 = stacking.fromLast();
00526 it2 != stacking.end();
00527 --it2 )
00528 {
00529 if( *it2 == *it )
00530 {
00531 it2 = stacking.end();
00532 break;
00533 }
00534 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00535 break;
00536 }
00537 }
00538
00539 if( it2 == stacking.end())
00540 {
00541 --it;
00542 continue;
00543 }
00544 Client* current = *it;
00545 ClientList::Iterator remove_it = it;
00546 --it;
00547 stacking.remove( remove_it );
00548 if( !current->transients().isEmpty())
00549 it = it2;
00550 ++it2;
00551 stacking.insert( it2, current );
00552 }
00553 #if 0
00554 kdDebug() << "stacking3:" << endl;
00555 for( ClientList::ConstIterator it = stacking.begin();
00556 it != stacking.end();
00557 ++it )
00558 kdDebug() << (void*)(*it) << *it << endl;
00559 kdDebug() << "\n\n" << endl;
00560 #endif
00561 return stacking;
00562 }
00563
00564 void Workspace::blockStackingUpdates( bool block )
00565 {
00566 if( block )
00567 {
00568 if( block_stacking_updates == 0 )
00569 blocked_propagating_new_clients = false;
00570 ++block_stacking_updates;
00571 }
00572 else
00573 if( --block_stacking_updates == 0 )
00574 updateStackingOrder( blocked_propagating_new_clients );
00575 }
00576
00577
00578 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00579 {
00580
00581 if( list.count() < 2 )
00582 return list;
00583
00584 ClientList result = list;
00585 for( ClientList::ConstIterator it = stacking_order.begin();
00586 it != stacking_order.end();
00587 ++it )
00588 if( result.remove( *it ) != 0 )
00589 result.append( *it );
00590 return result;
00591 }
00592
00593
00594
00595 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00596 {
00597
00598
00599
00600
00601 if( mainwindow->isTopMenu() && transient->groupTransient())
00602 return false;
00603 return true;
00604
00605
00606
00607
00608 if( mainwindow->isDock() && !mainwindow->keepBelow()
00609 && !mainwindow->isActive() && !transient->isActive())
00610 return false;
00611 return true;
00612 }
00613
00614
00615
00616
00617
00618 void Client::restackWindow( Window , int detail, NET::RequestSource source, bool send_event )
00619 {
00620 switch ( detail )
00621 {
00622 case Above:
00623 case TopIf:
00624 if( source == NET::FromTool )
00625 workspace()->raiseClient( this );
00626 else
00627 workspace()->raiseClientRequest( this );
00628 break;
00629 case Below:
00630 case BottomIf:
00631 if( source == NET::FromTool )
00632 workspace()->lowerClient( this );
00633 else
00634 workspace()->lowerClientRequest( this );
00635 break;
00636 case Opposite:
00637 default:
00638 break;
00639 }
00640 if( send_event )
00641 sendSyntheticConfigureNotify();
00642 }
00643
00644 void Client::setKeepAbove( bool b )
00645 {
00646 if ( b == keepAbove() )
00647 return;
00648 setKeepBelow( false );
00649 keep_above = b;
00650 info->setState( b ? NET::KeepAbove : 0, NET::KeepAbove );
00651
00652 workspace()->updateClientLayer( this );
00653 }
00654
00655 void Client::setKeepBelow( bool b )
00656 {
00657 if ( b == keepBelow() )
00658 return;
00659 setKeepAbove( false );
00660 keep_below = b;
00661 info->setState( b ? NET::KeepBelow : 0, NET::KeepBelow );
00662 workspace()->updateClientLayer( this );
00663 }
00664
00665 Layer Client::layer() const
00666 {
00667 if( in_layer == UnknownLayer )
00668 const_cast< Client* >( this )->in_layer = belongsToLayer();
00669 return in_layer;
00670 }
00671
00672 Layer Client::belongsToLayer() const
00673 {
00674 if( isDesktop())
00675 return DesktopLayer;
00676 if( isSplash())
00677 return NormalLayer;
00678 if( isDock() && keepBelow())
00679
00680
00681
00682 return NormalLayer;
00683 if( keepBelow())
00684 return BelowLayer;
00685 if( isDock() && !keepBelow())
00686 return DockLayer;
00687 if( isTopMenu())
00688 return DockLayer;
00689
00690
00691 bool raise_special_active_windows = ( workspace()->topClientOnDesktop( desktop(), true ) == this );
00692 if( keepAbove())
00693 return AboveLayer;
00694 if( isFullScreen() && workspace()->activeClient() != NULL
00695 && ( workspace()->activeClient() == this || this->hasTransient( workspace()->activeClient(), true ))
00696 && raise_special_active_windows )
00697 return ActiveLayer;
00698 return NormalLayer;
00699 }
00700
00701 }
This file is part of the documentation for kwin Library Version 3.2.3.