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, bool only_normal ) 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)->isShown( false ))
00216 {
00217 if( !only_normal )
00218 return *it;
00219 if( (*it)->wantsTabFocus() && !(*it)->isSpecialWindow())
00220 return *it;
00221 }
00222 }
00223 return 0;
00224 }
00225
00226 Client* Workspace::findDesktop( bool topmost, int desktop ) const
00227 {
00228
00229 if( topmost )
00230 {
00231 for ( ClientList::ConstIterator it = stacking_order.fromLast(); it != stacking_order.end(); --it)
00232 {
00233 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
00234 && (*it)->isShown( true ))
00235 return *it;
00236 }
00237 }
00238 else
00239 {
00240 for ( ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
00241 {
00242 if ( (*it)->isOnDesktop( desktop ) && (*it)->isDesktop()
00243 && (*it)->isShown( true ))
00244 return *it;
00245 }
00246 }
00247 return NULL;
00248 }
00249
00250 void Workspace::raiseOrLowerClient( Client *c)
00251 {
00252 if (!c) return;
00253 Client* topmost = NULL;
00254
00255 if ( most_recently_raised && stacking_order.contains( most_recently_raised ) &&
00256 most_recently_raised->isShown( true ) && c->isOnCurrentDesktop())
00257 topmost = most_recently_raised;
00258 else
00259 topmost = topClientOnDesktop( c->isOnAllDesktops() ? currentDesktop() : c->desktop());
00260
00261 if( c == topmost)
00262 lowerClient(c);
00263 else
00264 raiseClient(c);
00265 }
00266
00267
00268 void Workspace::lowerClient( Client* c )
00269 {
00270 if ( !c )
00271 return;
00272 if( c->isTopMenu())
00273 return;
00274
00275 c->cancelAutoRaise();
00276
00277 StackingUpdatesBlocker blocker( this );
00278
00279 unconstrained_stacking_order.remove( c );
00280 unconstrained_stacking_order.prepend( c );
00281 if( c->isTransient())
00282 {
00283
00284 ClientList mainclients = ensureStackingOrder( c->mainClients());
00285 for( ClientList::ConstIterator it = mainclients.fromLast();
00286 it != mainclients.end();
00287 ++it )
00288 lowerClient( *it );
00289 }
00290
00291 if ( c == most_recently_raised )
00292 most_recently_raised = 0;
00293 }
00294
00295 void Workspace::lowerClientWithinApplication( Client* c )
00296 {
00297 if ( !c )
00298 return;
00299 if( c->isTopMenu())
00300 return;
00301
00302 c->cancelAutoRaise();
00303
00304 StackingUpdatesBlocker blocker( this );
00305
00306 unconstrained_stacking_order.remove( c );
00307 bool lowered = false;
00308
00309 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00310 it != unconstrained_stacking_order.end();
00311 ++it )
00312 if( Client::belongToSameApplication( *it, c ))
00313 {
00314 unconstrained_stacking_order.insert( it, c );
00315 lowered = true;
00316 break;
00317 }
00318 if( !lowered )
00319 unconstrained_stacking_order.prepend( c );
00320
00321 }
00322
00323 void Workspace::raiseClient( Client* c )
00324 {
00325 if ( !c )
00326 return;
00327 if( c->isTopMenu())
00328 return;
00329
00330 c->cancelAutoRaise();
00331
00332 StackingUpdatesBlocker blocker( this );
00333
00334 if( c->isTransient())
00335 {
00336 ClientList mainclients = ensureStackingOrder( c->mainClients());
00337 for( ClientList::ConstIterator it = mainclients.begin();
00338 it != mainclients.end();
00339 ++it )
00340 raiseClient( *it );
00341 }
00342
00343 unconstrained_stacking_order.remove( c );
00344 unconstrained_stacking_order.append( c );
00345
00346 if( !c->isSpecialWindow())
00347 {
00348 most_recently_raised = c;
00349 pending_take_activity = NULL;
00350 }
00351 }
00352
00353 void Workspace::raiseClientWithinApplication( Client* c )
00354 {
00355 if ( !c )
00356 return;
00357 if( c->isTopMenu())
00358 return;
00359
00360 c->cancelAutoRaise();
00361
00362 StackingUpdatesBlocker blocker( this );
00363
00364
00365
00366 for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
00367 it != unconstrained_stacking_order.end();
00368 --it )
00369 {
00370 if( *it == c )
00371 return;
00372 if( Client::belongToSameApplication( *it, c ))
00373 {
00374 unconstrained_stacking_order.remove( c );
00375 ++it;
00376 unconstrained_stacking_order.insert( it, c );
00377 return;
00378 }
00379 }
00380 }
00381
00382 void Workspace::raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp )
00383 {
00384 if( src == NET::FromTool || allowFullClientRaising( c, timestamp ))
00385 raiseClient( c );
00386 else
00387 {
00388 raiseClientWithinApplication( c );
00389 c->demandAttention();
00390 }
00391 }
00392
00393 void Workspace::lowerClientRequest( Client* c, NET::RequestSource src, Time )
00394 {
00395
00396
00397
00398
00399 if( src == NET::FromTool || !c->hasUserTimeSupport())
00400 lowerClient( c );
00401 else
00402 lowerClientWithinApplication( c );
00403 }
00404
00405 void Workspace::restackClientUnderActive( Client* c )
00406 {
00407 if( c->isTopMenu())
00408 return;
00409 if( !active_client || active_client == c )
00410 {
00411 raiseClient( c );
00412 return;
00413 }
00414
00415 assert( unconstrained_stacking_order.contains( active_client ));
00416 if( Client::belongToSameApplication( active_client, c ))
00417 {
00418 unconstrained_stacking_order.remove( c );
00419 unconstrained_stacking_order.insert( unconstrained_stacking_order.find( active_client ), c );
00420 }
00421 else
00422 {
00423 for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00424 it != unconstrained_stacking_order.end();
00425 ++it )
00426 {
00427 if( Client::belongToSameApplication( active_client, *it ))
00428 {
00429 if( *it != c )
00430 {
00431 unconstrained_stacking_order.remove( c );
00432 unconstrained_stacking_order.insert( it, c );
00433 }
00434 break;
00435 }
00436 }
00437 }
00438 assert( unconstrained_stacking_order.contains( c ));
00439 for( int desktop = 1;
00440 desktop <= numberOfDesktops();
00441 ++desktop )
00442 {
00443 if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client ))
00444 {
00445 if( Client::belongToSameApplication( active_client, c ))
00446 {
00447 focus_chain[ desktop ].remove( c );
00448 focus_chain[ desktop ].insert( focus_chain[ desktop ].find( active_client ), c );
00449 }
00450 else
00451 {
00452 focus_chain[ desktop ].remove( c );
00453 for( ClientList::Iterator it = focus_chain[ desktop ].fromLast();
00454 it != focus_chain[ desktop ].end();
00455 --it )
00456 {
00457 if( Client::belongToSameApplication( active_client, *it ))
00458 {
00459 focus_chain[ desktop ].insert( it, c );
00460 break;
00461 }
00462 }
00463 }
00464 }
00465 }
00466
00467 if( c->wantsTabFocus() && global_focus_chain.contains( active_client ))
00468 {
00469 if( Client::belongToSameApplication( active_client, c ))
00470 {
00471 global_focus_chain.remove( c );
00472 global_focus_chain.insert( global_focus_chain.find( active_client ), c );
00473 }
00474 else
00475 {
00476 global_focus_chain.remove( c );
00477 for( ClientList::Iterator it = global_focus_chain.fromLast();
00478 it != global_focus_chain.end();
00479 --it )
00480 {
00481 if( Client::belongToSameApplication( active_client, *it ))
00482 {
00483 global_focus_chain.insert( it, c );
00484 break;
00485 }
00486 }
00487 }
00488 }
00489 updateStackingOrder();
00490 }
00491
00492 void Workspace::circulateDesktopApplications()
00493 {
00494 if ( desktops.count() > 1 )
00495 {
00496 bool change_active = activeClient()->isDesktop();
00497 raiseClient( findDesktop( false, currentDesktop()));
00498 if( change_active )
00499 activateClient( findDesktop( true, currentDesktop()));
00500 }
00501
00502 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00503 activateClient( findDesktop( true, currentDesktop()));
00504 }
00505
00506
00510 ClientList Workspace::constrainedStackingOrder()
00511 {
00512 ClientList layer[ NumLayers ];
00513
00514 #if 0
00515 kdDebug() << "stacking1:" << endl;
00516 #endif
00517
00518 QMap< Group*, Layer > minimum_layer;
00519 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00520 it != unconstrained_stacking_order.end();
00521 ++it )
00522 {
00523 Layer l = (*it)->layer();
00524
00525
00526
00527 if( minimum_layer.contains( (*it)->group())
00528 && minimum_layer[ (*it)->group() ] == ActiveLayer
00529 && ( l == NormalLayer || l == AboveLayer ))
00530 {
00531 l = minimum_layer[ (*it)->group() ];
00532 }
00533 minimum_layer[ (*it)->group() ] = l;
00534 layer[ l ].append( *it );
00535 }
00536 ClientList stacking;
00537 for( Layer lay = FirstLayer;
00538 lay < NumLayers;
00539 ++lay )
00540 stacking += layer[ lay ];
00541 #if 0
00542 kdDebug() << "stacking2:" << endl;
00543 for( ClientList::ConstIterator it = stacking.begin();
00544 it != stacking.end();
00545 ++it )
00546 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00547 #endif
00548
00549
00550 for( ClientList::Iterator it = stacking.fromLast();
00551 it != stacking.end();
00552 )
00553 {
00554 if( !(*it)->isTransient())
00555 {
00556 --it;
00557 continue;
00558 }
00559 ClientList::Iterator it2 = stacking.end();
00560 if( (*it)->groupTransient())
00561 {
00562 if( (*it)->group()->members().count() > 0 )
00563 {
00564 for( it2 = stacking.fromLast();
00565 it2 != stacking.end();
00566 --it2 )
00567 {
00568 if( *it2 == *it )
00569 {
00570 it2 = stacking.end();
00571 break;
00572 }
00573 if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
00574 break;
00575 }
00576 }
00577 }
00578 else
00579 {
00580 for( it2 = stacking.fromLast();
00581 it2 != stacking.end();
00582 --it2 )
00583 {
00584 if( *it2 == *it )
00585 {
00586 it2 = stacking.end();
00587 break;
00588 }
00589 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00590 break;
00591 }
00592 }
00593
00594 if( it2 == stacking.end())
00595 {
00596 --it;
00597 continue;
00598 }
00599 Client* current = *it;
00600 ClientList::Iterator remove_it = it;
00601 --it;
00602 stacking.remove( remove_it );
00603 if( !current->transients().isEmpty())
00604 it = it2;
00605 ++it2;
00606 stacking.insert( it2, current );
00607 }
00608 #if 0
00609 kdDebug() << "stacking3:" << endl;
00610 for( ClientList::ConstIterator it = stacking.begin();
00611 it != stacking.end();
00612 ++it )
00613 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00614 kdDebug() << "\n\n" << endl;
00615 #endif
00616 return stacking;
00617 }
00618
00619 void Workspace::blockStackingUpdates( bool block )
00620 {
00621 if( block )
00622 {
00623 if( block_stacking_updates == 0 )
00624 blocked_propagating_new_clients = false;
00625 ++block_stacking_updates;
00626 }
00627 else
00628 if( --block_stacking_updates == 0 )
00629 updateStackingOrder( blocked_propagating_new_clients );
00630 }
00631
00632
00633 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00634 {
00635
00636 if( list.count() < 2 )
00637 return list;
00638
00639 ClientList result = list;
00640 for( ClientList::ConstIterator it = stacking_order.begin();
00641 it != stacking_order.end();
00642 ++it )
00643 if( result.remove( *it ) != 0 )
00644 result.append( *it );
00645 return result;
00646 }
00647
00648
00649
00650 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00651 {
00652
00653
00654
00655
00656 if( mainwindow->isTopMenu() && transient->groupTransient())
00657 return false;
00658
00659 if( transient->isSplash() && mainwindow->isDialog())
00660 return false;
00661
00662
00663
00664
00665 if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
00666 return false;
00667
00668
00669 if( mainwindow->isDock())
00670 return false;
00671 return true;
00672 }
00673
00674
00675
00676
00677
00678 void Client::restackWindow( Window , int detail, NET::RequestSource src, Time timestamp, bool send_event )
00679 {
00680 switch ( detail )
00681 {
00682 case Above:
00683 case TopIf:
00684 workspace()->raiseClientRequest( this, src, timestamp );
00685 break;
00686 case Below:
00687 case BottomIf:
00688 workspace()->lowerClientRequest( this, src, timestamp );
00689 break;
00690 case Opposite:
00691 default:
00692 break;
00693 }
00694 if( send_event )
00695 sendSyntheticConfigureNotify();
00696 }
00697
00698 void Client::setKeepAbove( bool b )
00699 {
00700 b = rules()->checkKeepAbove( b );
00701 if( b && !rules()->checkKeepBelow( false ))
00702 setKeepBelow( false );
00703 if ( b == keepAbove())
00704 {
00705 if( bool( info->state() & NET::KeepAbove ) != keepAbove())
00706 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00707 return;
00708 }
00709 keep_above = b;
00710 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00711 if( decoration != NULL )
00712 decoration->emitKeepAboveChanged( keepAbove());
00713 workspace()->updateClientLayer( this );
00714 updateWindowRules();
00715 }
00716
00717 void Client::setKeepBelow( bool b )
00718 {
00719 b = rules()->checkKeepBelow( b );
00720 if( b && !rules()->checkKeepAbove( false ))
00721 setKeepAbove( false );
00722 if ( b == keepBelow())
00723 {
00724 if( bool( info->state() & NET::KeepBelow ) != keepBelow())
00725 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00726 return;
00727 }
00728 keep_below = b;
00729 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00730 if( decoration != NULL )
00731 decoration->emitKeepBelowChanged( keepBelow());
00732 workspace()->updateClientLayer( this );
00733 updateWindowRules();
00734 }
00735
00736 Layer Client::layer() const
00737 {
00738 if( in_layer == UnknownLayer )
00739 const_cast< Client* >( this )->in_layer = belongsToLayer();
00740 return in_layer;
00741 }
00742
00743 Layer Client::belongsToLayer() const
00744 {
00745 if( isDesktop())
00746 return DesktopLayer;
00747 if( isSplash())
00748 return NormalLayer;
00749 if( isDock() && keepBelow())
00750
00751
00752
00753 return NormalLayer;
00754 if( keepBelow())
00755 return BelowLayer;
00756 if( isDock() && !keepBelow())
00757 return DockLayer;
00758 if( isTopMenu())
00759 return DockLayer;
00760
00761
00762 const Client* ac = workspace()->mostRecentlyActivatedClient();
00763 const Client* top = workspace()->topClientOnDesktop( desktop(), true );
00764 if( isFullScreen() && ac != NULL && top != NULL
00765 && ( ac == this || this->group() == ac->group())
00766 && ( top == this || this->group() == top->group()))
00767 return ActiveLayer;
00768 if( keepAbove())
00769 return AboveLayer;
00770 return NormalLayer;
00771 }
00772
00773 }