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