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 <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 extern Time qt_x_time;
00077
00078 namespace KWinInternal
00079 {
00080
00081
00082
00083
00084
00085 void Workspace::updateClientLayer( Client* c )
00086 {
00087 if( c == NULL )
00088 return;
00089 if( c->layer() == c->belongsToLayer())
00090 return;
00091 StackingUpdatesBlocker blocker( this );
00092 c->invalidateLayer();
00093 for( ClientList::ConstIterator it = c->transients().begin();
00094 it != c->transients().end();
00095 ++it )
00096 updateClientLayer( *it );
00097 }
00098
00099 void Workspace::updateStackingOrder( bool propagate_new_clients )
00100 {
00101 if( block_stacking_updates > 0 )
00102 {
00103 blocked_propagating_new_clients = blocked_propagating_new_clients || propagate_new_clients;
00104 return;
00105 }
00106 ClientList new_stacking_order = constrainedStackingOrder();
00107 bool changed = ( new_stacking_order != stacking_order );
00108 stacking_order = new_stacking_order;
00109 #if 0
00110 kdDebug() << "stacking:" << changed << endl;
00111 if( changed || propagate_new_clients )
00112 {
00113 for( ClientList::ConstIterator it = stacking_order.begin();
00114 it != stacking_order.end();
00115 ++it )
00116 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00117 }
00118 #endif
00119 if( changed || propagate_new_clients )
00120 {
00121 propagateClients( propagate_new_clients );
00122 if( active_client )
00123 active_client->updateMouseGrab();
00124 }
00125 }
00126
00131 void Workspace::propagateClients( bool propagate_new_clients )
00132 {
00133 Window *cl;
00134
00135
00136
00137 Window* new_stack = new Window[ stacking_order.count() + 2 ];
00138 int pos = 0;
00139
00140
00141
00142
00143
00144 new_stack[ pos++ ] = supportWindow->winId();
00145 int topmenu_space_pos = 1;
00146 for( ClientList::ConstIterator it = stacking_order.fromLast();
00147 it != stacking_order.end();
00148 --it )
00149 {
00150 new_stack[ pos++ ] = (*it)->frameId();
00151 if( (*it)->belongsToLayer() >= DockLayer )
00152 topmenu_space_pos = pos;
00153 }
00154 if( topmenu_space != NULL )
00155 {
00156 for( int i = pos;
00157 i > topmenu_space_pos;
00158 --i )
00159 new_stack[ i ] = new_stack[ i - 1 ];
00160 new_stack[ topmenu_space_pos ] = topmenu_space->winId();
00161 ++pos;
00162 }
00163
00164
00165 assert( new_stack[ 0 ] = supportWindow->winId());
00166 XRestackWindows(qt_xdisplay(), new_stack, pos);
00167 delete [] new_stack;
00168
00169 if ( propagate_new_clients )
00170 {
00171 cl = new Window[ desktops.count() + clients.count()];
00172 pos = 0;
00173
00174 for ( ClientList::ConstIterator it = desktops.begin(); it != desktops.end(); ++it )
00175 cl[pos++] = (*it)->window();
00176 for ( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it )
00177 cl[pos++] = (*it)->window();
00178 rootInfo->setClientList( cl, pos );
00179 delete [] cl;
00180 }
00181
00182 cl = new Window[ stacking_order.count()];
00183 pos = 0;
00184 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
00185 cl[pos++] = (*it)->window();
00186 rootInfo->setClientListStacking( cl, pos );
00187 delete [] cl;
00188 }
00189
00190
00196
00197 Client* Workspace::topClientOnDesktop( int desktop, bool unconstrained ) const
00198 {
00199
00200 ClientList::ConstIterator begin, end;
00201 if( !unconstrained )
00202 {
00203 begin = stacking_order.fromLast();
00204 end = stacking_order.end();
00205 }
00206 else
00207 {
00208 begin = unconstrained_stacking_order.fromLast();
00209 end = unconstrained_stacking_order.end();
00210 }
00211 for( ClientList::ConstIterator it = begin;
00212 it != end;
00213 --it )
00214 {
00215 if ( (*it)->isOnDesktop( desktop ) && !(*it)->isSpecialWindow()
00216 && (*it)->isShown( false ) && (*it)->wantsTabFocus())
00217 return *it;
00218 }
00219 return 0;
00220 }
00221
00222 Client* Workspace::findDesktop( bool topmost, int desktop ) const
00223 {
00224
00225 if( topmost )
00226 {
00227 for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
00228 {
00229 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
00230 && (*it)->isShown( true ))
00231 return *it;
00232 }
00233 }
00234 else
00235 {
00236 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
00237 {
00238 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
00239 && (*it)->isShown( true ))
00240 return *it;
00241 }
00242 }
00243 return NULL;
00244 }
00245
00246 void Workspace::raiseOrLowerClient( Client *c)
00247 {
00248 if (!c) return;
00249 Client* topmost = NULL;
00250
00251 if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
00252 most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
00253 topmost = most_recently_raised;
00254 else
00255 topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
00256
00257 if( c == topmost)
00258 lowerClient(c);
00259 else
00260 raiseClient(c);
00261 }
00262
00263
00264 void Workspace::lowerClient( Client* c )
00265 {
00266 if ( !c )
00267 return;
00268 if( c->isTopMenu())
00269 return;
00270
00271 c->cancelAutoRaise();
00272
00273 StackingUpdatesBlocker blocker( this );
00274
00275 unconstrained_stacking_order.remove( c );
00276 unconstrained_stacking_order.prepend( c );
00277 if( c->isTransient())
00278 {
00279
00280 ClientList mainclients = ensureStackingOrder( c->mainClients());
00281 for( ClientList::ConstIterator it = mainclients.fromLast();
00282 it != mainclients.end();
00283 ++it )
00284 lowerClient( *it );
00285 }
00286
00287 if ( c == most_recently_raised )
00288 most_recently_raised = 0;
00289 }
00290
00291 void Workspace::lowerClientWithinApplication( Client* c )
00292 {
00293 if ( !c )
00294 return;
00295 if( c->isTopMenu())
00296 return;
00297
00298 c->cancelAutoRaise();
00299
00300 StackingUpdatesBlocker blocker( this );
00301
00302 unconstrained_stacking_order.remove( c );
00303 bool lowered = false;
00304
00305 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00306 it != unconstrained_stacking_order.end();
00307 ++it )
00308 if( Client::belongToSameApplication( *it, c ))
00309 {
00310 unconstrained_stacking_order.insert( it, c );
00311 lowered = true;
00312 break;
00313 }
00314 if( !lowered )
00315 unconstrained_stacking_order.prepend( c );
00316
00317 }
00318
00319 void Workspace::raiseClient( Client* c )
00320 {
00321 if ( !c )
00322 return;
00323 if( c->isTopMenu())
00324 return;
00325
00326 c->cancelAutoRaise();
00327
00328 StackingUpdatesBlocker blocker( this );
00329
00330 if( c->isTransient())
00331 {
00332 ClientList mainclients = ensureStackingOrder( c->mainClients());
00333 for( ClientList::ConstIterator it = mainclients.begin();
00334 it != mainclients.end();
00335 ++it )
00336 raiseClient( *it );
00337 }
00338
00339 unconstrained_stacking_order.remove( c );
00340 unconstrained_stacking_order.append( c );
00341
00342 if( !c->isSpecialWindow())
00343 {
00344 most_recently_raised = c;
00345 pending_take_activity = NULL;
00346 }
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, NET::RequestSource src, Time timestamp )
00379 {
00380 if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
00381 raiseClient( c );
00382 else
00383 {
00384 raiseClientWithinApplication( c );
00385 c->demandAttention();
00386 }
00387 }
00388
00389 void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time )
00390 {
00391
00392
00393
00394
00395 if( src == NET::FromTool || !c->hasUserTimeSupport())
00396 lowerClient( c );
00397 else
00398 lowerClientWithinApplication( 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 assert( unconstrained_stacking_order.contains( active_client ));
00412 if( Client::belongToSameApplication( active_client, c ))
00413 {
00414 unconstrained_stacking_order.remove( c );
00415 unconstrained_stacking_order.insert( unconstrained_stacking_order.find( active_client ), c );
00416 }
00417 else
00418 {
00419 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00420 it != unconstrained_stacking_order.end();
00421 ++it )
00422 {
00423 if( Client::belongToSameApplication( active_client, *it ))
00424 {
00425 if( *it != c )
00426 {
00427 unconstrained_stacking_order.remove( c );
00428 unconstrained_stacking_order.insert( it, c );
00429 }
00430 break;
00431 }
00432 }
00433 }
00434 assert( unconstrained_stacking_order.contains( c ));
00435 for( int desktop = 1;
00436 desktop <= numberOfDesktops();
00437 ++desktop )
00438 {
00439 if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client ))
00440 {
00441 if( Client::belongToSameApplication( active_client, c ))
00442 {
00443 focus_chain[ desktop ].remove( c );
00444 focus_chain[ desktop ].insert( focus_chain[ desktop ].find( active_client ), c );
00445 }
00446 else
00447 {
00448 focus_chain[ desktop ].remove( c );
00449 for( ClientList::Iterator it = focus_chain[ desktop ].fromLast();
00450 it != focus_chain[ desktop ].end();
00451 --it )
00452 {
00453 if( Client::belongToSameApplication( active_client, *it ))
00454 {
00455 focus_chain[ desktop ].insert( it, c );
00456 break;
00457 }
00458 }
00459 }
00460 }
00461 }
00462
00463 if( c->wantsTabFocus() && global_focus_chain.contains( active_client ))
00464 {
00465 if( Client::belongToSameApplication( active_client, c ))
00466 {
00467 global_focus_chain.remove( c );
00468 global_focus_chain.insert( global_focus_chain.find( active_client ), c );
00469 }
00470 else
00471 {
00472 global_focus_chain.remove( c );
00473 for( ClientList::Iterator it = global_focus_chain.fromLast();
00474 it != global_focus_chain.end();
00475 --it )
00476 {
00477 if( Client::belongToSameApplication( active_client, *it ))
00478 {
00479 global_focus_chain.insert( it, c );
00480 break;
00481 }
00482 }
00483 }
00484 }
00485 updateStackingOrder();
00486 }
00487
00488 void Workspace::circulateDesktopApplications()
00489 {
00490 if ( desktops.count() > 1 )
00491 {
00492 bool change_active = activeClient()->isDesktop();
00493 raiseClient( findDesktop( false, currentDesktop()));
00494 if( change_active )
00495 activateClient( findDesktop( true, currentDesktop()));
00496 }
00497
00498 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00499 activateClient( findDesktop( true, currentDesktop()));
00500 }
00501
00502
00506 ClientList Workspace::constrainedStackingOrder()
00507 {
00508 ClientList layer[ NumLayers ];
00509
00510 #if 0
00511 kdDebug() << "stacking1:" << endl;
00512 #endif
00513
00514 QMap< Group*, Layer > minimum_layer;
00515 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00516 it != unconstrained_stacking_order.end();
00517 ++it )
00518 {
00519 Layer l = (*it)->layer();
00520
00521
00522
00523 if( minimum_layer.contains( (*it)->group())
00524 && minimum_layer[ (*it)->group() ] == ActiveLayer
00525 && ( l == NormalLayer || l == AboveLayer ))
00526 {
00527 l = minimum_layer[ (*it)->group() ];
00528 }
00529 minimum_layer[ (*it)->group() ] = l;
00530 layer[ l ].append( *it );
00531 }
00532 ClientList stacking;
00533 for( Layer lay = FirstLayer;
00534 lay < NumLayers;
00535 ++lay )
00536 stacking += layer[ lay ];
00537 #if 0
00538 kdDebug() << "stacking2:" << endl;
00539 for( ClientList::ConstIterator it = stacking.begin();
00540 it != stacking.end();
00541 ++it )
00542 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00543 #endif
00544
00545
00546 for( ClientList::Iterator it = stacking.fromLast();
00547 it != stacking.end();
00548 )
00549 {
00550 if( !(*it)->isTransient())
00551 {
00552 --it;
00553 continue;
00554 }
00555 ClientList::Iterator it2 = stacking.end();
00556 if( (*it)->groupTransient())
00557 {
00558 if( (*it)->group()->members().count() > 0 )
00559 {
00560 for( it2 = stacking.fromLast();
00561 it2 != stacking.end();
00562 --it2 )
00563 {
00564 if( *it2 == *it )
00565 {
00566 it2 = stacking.end();
00567 break;
00568 }
00569 if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
00570 break;
00571 }
00572 }
00573 }
00574 else
00575 {
00576 for( it2 = stacking.fromLast();
00577 it2 != stacking.end();
00578 --it2 )
00579 {
00580 if( *it2 == *it )
00581 {
00582 it2 = stacking.end();
00583 break;
00584 }
00585 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00586 break;
00587 }
00588 }
00589
00590 if( it2 == stacking.end())
00591 {
00592 --it;
00593 continue;
00594 }
00595 Client* current = *it;
00596 ClientList::Iterator remove_it = it;
00597 --it;
00598 stacking.remove( remove_it );
00599 if( !current->transients().isEmpty())
00600 it = it2;
00601 ++it2;
00602 stacking.insert( it2, current );
00603 }
00604 #if 0
00605 kdDebug() << "stacking3:" << endl;
00606 for( ClientList::ConstIterator it = stacking.begin();
00607 it != stacking.end();
00608 ++it )
00609 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00610 kdDebug() << "\n\n" << endl;
00611 #endif
00612 return stacking;
00613 }
00614
00615 void Workspace::blockStackingUpdates( bool block )
00616 {
00617 if( block )
00618 {
00619 if( block_stacking_updates == 0 )
00620 blocked_propagating_new_clients = false;
00621 ++block_stacking_updates;
00622 }
00623 else
00624 if( --block_stacking_updates == 0 )
00625 updateStackingOrder( blocked_propagating_new_clients );
00626 }
00627
00628
00629 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00630 {
00631
00632 if( list.count() < 2 )
00633 return list;
00634
00635 ClientList result = list;
00636 for( ClientList::ConstIterator it = stacking_order.begin();
00637 it != stacking_order.end();
00638 ++it )
00639 if( result.remove( *it ) != 0 )
00640 result.append( *it );
00641 return result;
00642 }
00643
00644
00645
00646 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00647 {
00648
00649
00650
00651
00652 if( mainwindow->isTopMenu() && transient->groupTransient())
00653 return false;
00654
00655 if( transient->isSplash() && mainwindow->isDialog())
00656 return false;
00657
00658
00659
00660
00661 if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
00662 return false;
00663
00664
00665 if( mainwindow->isDock())
00666 return false;
00667 return true;
00668 }
00669
00670
00671
00672
00673
00674 void Client::restackWindow( Window , int detail, NET::RequestSource src, Time timestamp, bool send_event )
00675 {
00676 switch ( detail )
00677 {
00678 case Above:
00679 case TopIf:
00680 workspace()->raiseClientRequest( this, src, timestamp );
00681 break;
00682 case Below:
00683 case BottomIf:
00684 workspace()->lowerClientRequest( this, src, timestamp );
00685 break;
00686 case Opposite:
00687 default:
00688 break;
00689 }
00690 if( send_event )
00691 sendSyntheticConfigureNotify();
00692 }
00693
00694 void Client::setKeepAbove( bool b )
00695 {
00696 b = rules()->checkKeepAbove( b );
00697 if( b && !rules()->checkKeepBelow( false ))
00698 setKeepBelow( false );
00699 if ( b == keepAbove())
00700 {
00701 if( bool( info->state() & NET::KeepAbove ) != keepAbove())
00702 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00703 return;
00704 }
00705 keep_above = b;
00706 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00707 if( decoration != NULL )
00708 decoration->emitKeepAboveChanged( keepAbove());
00709 workspace()->updateClientLayer( this );
00710 updateWindowRules();
00711 }
00712
00713 void Client::setKeepBelow( bool b )
00714 {
00715 b = rules()->checkKeepBelow( b );
00716 if( b && !rules()->checkKeepAbove( false ))
00717 setKeepAbove( false );
00718 if ( b == keepBelow())
00719 {
00720 if( bool( info->state() & NET::KeepBelow ) != keepBelow())
00721 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00722 return;
00723 }
00724 keep_below = b;
00725 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00726 if( decoration != NULL )
00727 decoration->emitKeepBelowChanged( keepBelow());
00728 workspace()->updateClientLayer( this );
00729 updateWindowRules();
00730 }
00731
00732 Layer Client::layer() const
00733 {
00734 if( in_layer == UnknownLayer )
00735 const_cast< Client* >( this )->in_layer = belongsToLayer();
00736 return in_layer;
00737 }
00738
00739 Layer Client::belongsToLayer() const
00740 {
00741 if( isDesktop())
00742 return DesktopLayer;
00743 if( isSplash())
00744 return NormalLayer;
00745 if( isDock() && keepBelow())
00746
00747
00748
00749 return NormalLayer;
00750 if( keepBelow())
00751 return BelowLayer;
00752 if( isDock() && !keepBelow())
00753 return DockLayer;
00754 if( isTopMenu())
00755 return DockLayer;
00756
00757
00758 const Client* ac = workspace()->mostRecentlyActivatedClient();
00759 const Client* top = workspace()->topClientOnDesktop( desktop(), true );
00760 if( isFullScreen() && ac != NULL && top != NULL
00761 && ( ac == this || this->group() == ac->group())
00762 && ( top == this || this->group() == top->group()))
00763 return ActiveLayer;
00764 if( keepAbove())
00765 return AboveLayer;
00766 return NormalLayer;
00767 }
00768
00769 }