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 |= 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 if( c->wantsTabFocus() && focus_chain.contains( active_client ))
00425 {
00426
00427 focus_chain.remove( c );
00428 for( ClientList::Iterator it = focus_chain.fromLast();
00429 it != focus_chain.end();
00430 --it )
00431 {
00432 if( Client::belongToSameApplication( active_client, *it ))
00433 {
00434 focus_chain.insert( it, c );
00435 break;
00436 }
00437 }
00438 }
00439 updateStackingOrder();
00440 }
00441
00442 void Workspace::circulateDesktopApplications()
00443 {
00444 if ( desktops.count() > 1 )
00445 {
00446 bool change_active = activeClient()->isDesktop();
00447 raiseClient( findDesktop( false, currentDesktop()));
00448 if( change_active )
00449 activateClient( findDesktop( true, currentDesktop()));
00450 }
00451
00452 if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00453 activateClient( findDesktop( true, currentDesktop()));
00454 }
00455
00456
00460 ClientList Workspace::constrainedStackingOrder()
00461 {
00462 ClientList layer[ NumLayers ];
00463
00464 #if 0
00465 kdDebug() << "stacking1:" << endl;
00466 #endif
00467
00468 QMap< Group*, Layer > minimum_layer;
00469 for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00470 it != unconstrained_stacking_order.end();
00471 ++it )
00472 {
00473 Layer l = (*it)->layer();
00474
00475
00476
00477 if( minimum_layer.contains( (*it)->group())
00478 && minimum_layer[ (*it)->group() ] == ActiveLayer
00479 && ( l == NormalLayer || l == AboveLayer ))
00480 {
00481 l = minimum_layer[ (*it)->group() ];
00482 }
00483 minimum_layer[ (*it)->group() ] = l;
00484 layer[ l ].append( *it );
00485 }
00486 ClientList stacking;
00487 for( Layer lay = FirstLayer;
00488 lay < NumLayers;
00489 ++lay )
00490 stacking += layer[ lay ];
00491 #if 0
00492 kdDebug() << "stacking2:" << endl;
00493 for( ClientList::ConstIterator it = stacking.begin();
00494 it != stacking.end();
00495 ++it )
00496 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00497 #endif
00498
00499
00500 for( ClientList::Iterator it = stacking.fromLast();
00501 it != stacking.end();
00502 )
00503 {
00504 if( !(*it)->isTransient())
00505 {
00506 --it;
00507 continue;
00508 }
00509 ClientList::Iterator it2 = stacking.end();
00510 if( (*it)->groupTransient())
00511 {
00512 if( (*it)->group()->members().count() > 0 )
00513 {
00514 for( it2 = stacking.fromLast();
00515 it2 != stacking.end();
00516 --it2 )
00517 {
00518 if( *it2 == *it )
00519 {
00520 it2 = stacking.end();
00521 break;
00522 }
00523 if( (*it2)->hasTransient( *it, true ) && keepTransientAbove( *it2, *it ))
00524 break;
00525 }
00526 }
00527 }
00528 else
00529 {
00530 for( it2 = stacking.fromLast();
00531 it2 != stacking.end();
00532 --it2 )
00533 {
00534 if( *it2 == *it )
00535 {
00536 it2 = stacking.end();
00537 break;
00538 }
00539 if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00540 break;
00541 }
00542 }
00543
00544 if( it2 == stacking.end())
00545 {
00546 --it;
00547 continue;
00548 }
00549 Client* current = *it;
00550 ClientList::Iterator remove_it = it;
00551 --it;
00552 stacking.remove( remove_it );
00553 if( !current->transients().isEmpty())
00554 it = it2;
00555 ++it2;
00556 stacking.insert( it2, current );
00557 }
00558 #if 0
00559 kdDebug() << "stacking3:" << endl;
00560 for( ClientList::ConstIterator it = stacking.begin();
00561 it != stacking.end();
00562 ++it )
00563 kdDebug() << (void*)(*it) << *it << ":" << (*it)->layer() << endl;
00564 kdDebug() << "\n\n" << endl;
00565 #endif
00566 return stacking;
00567 }
00568
00569 void Workspace::blockStackingUpdates( bool block )
00570 {
00571 if( block )
00572 {
00573 if( block_stacking_updates == 0 )
00574 blocked_propagating_new_clients = false;
00575 ++block_stacking_updates;
00576 }
00577 else
00578 if( --block_stacking_updates == 0 )
00579 updateStackingOrder( blocked_propagating_new_clients );
00580 }
00581
00582
00583 ClientList Workspace::ensureStackingOrder( const ClientList& list ) const
00584 {
00585
00586 if( list.count() < 2 )
00587 return list;
00588
00589 ClientList result = list;
00590 for( ClientList::ConstIterator it = stacking_order.begin();
00591 it != stacking_order.end();
00592 ++it )
00593 if( result.remove( *it ) != 0 )
00594 result.append( *it );
00595 return result;
00596 }
00597
00598
00599
00600 bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* transient )
00601 {
00602
00603
00604
00605
00606 if( mainwindow->isTopMenu() && transient->groupTransient())
00607 return false;
00608
00609 if( transient->isSplash() && mainwindow->isDialog())
00610 return false;
00611
00612
00613
00614
00615 if( transient->isDialog() && !transient->isModal() && transient->groupTransient())
00616 return false;
00617
00618
00619 if( mainwindow->isDock())
00620 return false;
00621 return true;
00622 }
00623
00624
00625
00626
00627
00628 void Client::restackWindow( Window , int detail, NET::RequestSource src, Time timestamp, bool send_event )
00629 {
00630 switch ( detail )
00631 {
00632 case Above:
00633 case TopIf:
00634 workspace()->raiseClientRequest( this, src, timestamp );
00635 break;
00636 case Below:
00637 case BottomIf:
00638 workspace()->lowerClientRequest( this, src, timestamp );
00639 break;
00640 case Opposite:
00641 default:
00642 break;
00643 }
00644 if( send_event )
00645 sendSyntheticConfigureNotify();
00646 }
00647
00648 void Client::setKeepAbove( bool b )
00649 {
00650 b = rules()->checkKeepAbove( b );
00651 if( b && !rules()->checkKeepBelow( false ))
00652 setKeepBelow( false );
00653 if ( b == keepAbove())
00654 {
00655 if( bool( info->state() & NET::KeepAbove ) != keepAbove())
00656 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00657 return;
00658 }
00659 keep_above = b;
00660 info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
00661 if( decoration != NULL )
00662 decoration->emitKeepAboveChanged( keepAbove());
00663 workspace()->updateClientLayer( this );
00664 updateWindowRules();
00665 }
00666
00667 void Client::setKeepBelow( bool b )
00668 {
00669 b = rules()->checkKeepBelow( b );
00670 if( b && !rules()->checkKeepAbove( false ))
00671 setKeepAbove( false );
00672 if ( b == keepBelow())
00673 {
00674 if( bool( info->state() & NET::KeepBelow ) != keepBelow())
00675 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00676 return;
00677 }
00678 keep_below = b;
00679 info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
00680 if( decoration != NULL )
00681 decoration->emitKeepBelowChanged( keepBelow());
00682 workspace()->updateClientLayer( this );
00683 updateWindowRules();
00684 }
00685
00686 Layer Client::layer() const
00687 {
00688 if( in_layer == UnknownLayer )
00689 const_cast< Client* >( this )->in_layer = belongsToLayer();
00690 return in_layer;
00691 }
00692
00693 Layer Client::belongsToLayer() const
00694 {
00695 if( isDesktop())
00696 return DesktopLayer;
00697 if( isSplash())
00698 return NormalLayer;
00699 if( isDock() && keepBelow())
00700
00701
00702
00703 return NormalLayer;
00704 if( keepBelow())
00705 return BelowLayer;
00706 if( isDock() && !keepBelow())
00707 return DockLayer;
00708 if( isTopMenu())
00709 return DockLayer;
00710
00711
00712 const Client* ac = workspace()->mostRecentlyActivatedClient();
00713 const Client* top = workspace()->topClientOnDesktop( desktop(), true );
00714 if( isFullScreen() && ac != NULL && top != NULL
00715 && ( ac == this || this->group() == ac->group())
00716 && ( top == this || this->group() == top->group()))
00717 return ActiveLayer;
00718 if( keepAbove())
00719 return AboveLayer;
00720 return NormalLayer;
00721 }
00722
00723 }