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