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