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