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
if( c->isTopMenu())
00272
return;
00273
00274 c->cancelAutoRaise();
00275
00276 StackingUpdatesBlocker blocker(
this );
00277
00278 unconstrained_stacking_order.remove( c );
00279 unconstrained_stacking_order.prepend( c );
00280
if( c->isTransient())
00281 {
00282
00283 ClientList mainclients = ensureStackingOrder( c->mainClients());
00284
for( ClientList::ConstIterator it = mainclients.fromLast();
00285 it != mainclients.end();
00286 ++it )
00287 lowerClient( *it );
00288 }
00289
00290
if ( c == most_recently_raised )
00291 most_recently_raised = 0;
00292 }
00293
00294
void Workspace::lowerClientWithinApplication( Client* c )
00295 {
00296
if ( !c )
00297
return;
00298
if( c->isTopMenu())
00299
return;
00300
00301 c->cancelAutoRaise();
00302
00303 StackingUpdatesBlocker blocker(
this );
00304
00305 unconstrained_stacking_order.remove( c );
00306
bool lowered =
false;
00307
00308
for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00309 it != unconstrained_stacking_order.end();
00310 ++it )
00311
if( Client::belongToSameApplication( *it, c ))
00312 {
00313 unconstrained_stacking_order.insert( it, c );
00314 lowered =
true;
00315
break;
00316 }
00317
if( !lowered )
00318 unconstrained_stacking_order.prepend( c );
00319
00320 }
00321
00322
void Workspace::raiseClient( 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
if( c->isTransient())
00334 {
00335 ClientList mainclients = ensureStackingOrder( c->mainClients());
00336
for( ClientList::ConstIterator it = mainclients.begin();
00337 it != mainclients.end();
00338 ++it )
00339 raiseClient( *it );
00340 }
00341
00342 unconstrained_stacking_order.remove( c );
00343 unconstrained_stacking_order.append( c );
00344
00345
if( !c->isSpecialWindow())
00346 most_recently_raised = c;
00347 }
00348
00349
void Workspace::raiseClientWithinApplication( 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
00361
00362
for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
00363 it != unconstrained_stacking_order.end();
00364 --it )
00365 {
00366
if( *it == c )
00367
return;
00368
if( Client::belongToSameApplication( *it, c ))
00369 {
00370 unconstrained_stacking_order.remove( c );
00371 ++it;
00372 unconstrained_stacking_order.insert( it, c );
00373
return;
00374 }
00375 }
00376 }
00377
00378
void Workspace::raiseClientRequest( Client* c )
00379 {
00380
if( allowFullClientRaising( c ))
00381 raiseClient( c );
00382
else
00383 {
00384 raiseClientWithinApplication( c );
00385 c->demandAttention();
00386 }
00387 }
00388
00389
void Workspace::lowerClientRequest( Client* c )
00390 {
00391
00392
00393
00394
00395
if( c->hasUserTimeSupport())
00396 lowerClientWithinApplication( c );
00397
else
00398 lowerClient( c );
00399 }
00400
00401
void Workspace::restackClientUnderActive( Client* c )
00402 {
00403
if( c->isTopMenu())
00404
return;
00405
if( !active_client || active_client == c )
00406 {
00407 raiseClient( c );
00408
return;
00409 }
00410
00411
00412 assert( unconstrained_stacking_order.contains( active_client ));
00413
for( ClientList::Iterator it = unconstrained_stacking_order.begin();
00414 it != unconstrained_stacking_order.end();
00415 ++it )
00416 {
00417
if( Client::belongToSameApplication( active_client, *it ))
00418 {
00419
if( *it != c )
00420 {
00421 unconstrained_stacking_order.remove( c );
00422 unconstrained_stacking_order.insert( it, c );
00423 }
00424
break;
00425 }
00426 }
00427 assert( unconstrained_stacking_order.contains( c ));
00428
if( c->wantsTabFocus() && focus_chain.contains( active_client ))
00429 {
00430
00431 focus_chain.remove( c );
00432
for( ClientList::Iterator it = focus_chain.fromLast();
00433 it != focus_chain.end();
00434 --it )
00435 {
00436
if( Client::belongToSameApplication( active_client, *it ))
00437 {
00438 focus_chain.insert( it, c );
00439
break;
00440 }
00441 }
00442 }
00443 updateStackingOrder();
00444 }
00445
00446
void Workspace::circulateDesktopApplications()
00447 {
00448
if ( desktops.count() > 1 )
00449 {
00450
bool change_active = activeClient()->isDesktop();
00451 raiseClient( findDesktop(
false, currentDesktop()));
00452
if( change_active )
00453 activateClient( findDesktop(
true, currentDesktop()));
00454 }
00455
00456
if( desktops.count() > 0 && activeClient() == NULL && should_get_focus.count() == 0 )
00457 activateClient( findDesktop(
true, currentDesktop()));
00458 }
00459
00460
00464 ClientList Workspace::constrainedStackingOrder()
00465 {
00466 ClientList layer[ NumLayers ];
00467
00468
#if 0
00469
kdDebug() <<
"stacking1:" << endl;
00470
#endif
00471
00472
for( ClientList::ConstIterator it = unconstrained_stacking_order.begin();
00473 it != unconstrained_stacking_order.end();
00474 ++it )
00475 {
00476
#if 0
00477
kdDebug() << (
void*)(*it) << *it << endl;
00478
#endif
00479
layer[ (*it)->layer() ].append( *it );
00480 }
00481 ClientList stacking;
00482
for( Layer lay = FirstLayer;
00483 lay < NumLayers;
00484 ++lay )
00485 stacking += layer[ lay ];
00486
#if 0
00487
kdDebug() <<
"stacking2:" << endl;
00488
for( ClientList::ConstIterator it = stacking.begin();
00489 it != stacking.end();
00490 ++it )
00491 kdDebug() << (
void*)(*it) << *it << endl;
00492
#endif
00493
00494
00495
for( ClientList::Iterator it = stacking.fromLast();
00496 it != stacking.end();
00497 )
00498 {
00499
if( !(*it)->isTransient())
00500 {
00501 --it;
00502
continue;
00503 }
00504 ClientList::Iterator it2 = stacking.end();
00505
if( (*it)->groupTransient())
00506 {
00507
if( (*it)->group()->members().count() > 0 )
00508 {
00509
for( it2 = stacking.fromLast();
00510 it2 != stacking.end();
00511 --it2 )
00512 {
00513
if( *it2 == *it )
00514 {
00515 it2 = stacking.end();
00516
break;
00517 }
00518
if( (*it2)->hasTransient( *it,
true ) && keepTransientAbove( *it2, *it ))
00519
break;
00520 }
00521 }
00522 }
00523
else
00524 {
00525
for( it2 = stacking.fromLast();
00526 it2 != stacking.end();
00527 --it2 )
00528 {
00529
if( *it2 == *it )
00530 {
00531 it2 = stacking.end();
00532
break;
00533 }
00534
if( *it2 == (*it)->transientFor() && keepTransientAbove( *it2, *it ))
00535
break;
00536 }
00537 }
00538
00539
if( it2 == stacking.end())
00540 {
00541 --it;
00542
continue;
00543 }
00544 Client* current = *it;
00545 ClientList::Iterator remove_it = it;
00546 --it;
00547 stacking.remove( remove_it );
00548
if( !current->transients().isEmpty())
00549 it = it2;
00550 ++it2;
00551 stacking.insert( it2, current );
00552 }
00553
#if 0
00554
kdDebug() <<
"stacking3:" << endl;
00555
for( ClientList::ConstIterator it = stacking.begin();
00556 it != stacking.end();
00557 ++it )
00558 kdDebug() << (
void*)(*it) << *it << endl;
00559 kdDebug() <<
"\n\n" << endl;
00560
#endif
00561
return stacking;
00562 }
00563
00564
void Workspace::blockStackingUpdates(
bool block )
00565 {
00566
if( block )
00567 {
00568
if( block_stacking_updates == 0 )
00569 blocked_propagating_new_clients =
false;
00570 ++block_stacking_updates;
00571 }
00572
else
00573
if( --block_stacking_updates == 0 )
00574 updateStackingOrder( blocked_propagating_new_clients );
00575 }
00576
00577
00578 ClientList Workspace::ensureStackingOrder(
const ClientList& list )
const
00579
{
00580
00581
if( list.count() < 2 )
00582
return list;
00583
00584 ClientList result = list;
00585
for( ClientList::ConstIterator it = stacking_order.begin();
00586 it != stacking_order.end();
00587 ++it )
00588
if( result.remove( *it ) != 0 )
00589 result.append( *it );
00590
return result;
00591 }
00592
00593
00594
00595
bool Workspace::keepTransientAbove(
const Client* mainwindow,
const Client*
transient )
00596 {
00597
00598
00599
00600
00601
if( mainwindow->isTopMenu() &&
transient->groupTransient())
00602
return false;
00603
return true;
00604
00605
00606
00607
00608
if( mainwindow->isDock() && !mainwindow->keepBelow()
00609 && !mainwindow->isActive() && !
transient->isActive())
00610
return false;
00611
return true;
00612 }
00613
00614
00615
00616
00617
00618
void Client::restackWindow( Window ,
int detail, NET::RequestSource source,
bool send_event )
00619 {
00620
switch ( detail )
00621 {
00622
case Above:
00623
case TopIf:
00624
if( source == NET::FromTool )
00625 workspace()->raiseClient(
this );
00626
else
00627 workspace()->raiseClientRequest(
this );
00628
break;
00629
case Below:
00630
case BottomIf:
00631
if( source == NET::FromTool )
00632 workspace()->lowerClient(
this );
00633
else
00634 workspace()->lowerClientRequest(
this );
00635
break;
00636
case Opposite:
00637
default:
00638
break;
00639 }
00640
if( send_event )
00641 sendSyntheticConfigureNotify();
00642 }
00643
00644
void Client::setKeepAbove(
bool b )
00645 {
00646
if ( b ==
keepAbove() )
00647
return;
00648
setKeepBelow(
false );
00649 keep_above = b;
00650 info->setState( b ? NET::KeepAbove : 0, NET::KeepAbove );
00651
00652 workspace()->updateClientLayer(
this );
00653 }
00654
00655
void Client::setKeepBelow(
bool b )
00656 {
00657
if ( b ==
keepBelow() )
00658
return;
00659
setKeepAbove(
false );
00660 keep_below = b;
00661 info->setState( b ? NET::KeepBelow : 0, NET::KeepBelow );
00662 workspace()->updateClientLayer(
this );
00663 }
00664
00665 Layer Client::layer()
const
00666
{
00667
if( in_layer == UnknownLayer )
00668 const_cast< Client* >(
this )->in_layer = belongsToLayer();
00669
return in_layer;
00670 }
00671
00672 Layer Client::belongsToLayer()
const
00673
{
00674
if( isDesktop())
00675
return DesktopLayer;
00676
if( isSplash())
00677
return NormalLayer;
00678
if( isDock() &&
keepBelow())
00679
00680
00681
00682
return NormalLayer;
00683
if(
keepBelow())
00684
return BelowLayer;
00685
if( isDock() && !
keepBelow())
00686
return DockLayer;
00687
if( isTopMenu())
00688
return DockLayer;
00689
00690
00691
bool raise_special_active_windows = ( workspace()->topClientOnDesktop(
desktop(),
true ) ==
this );
00692
if(
keepAbove())
00693
return AboveLayer;
00694
if( isFullScreen() && workspace()->activeClient() != NULL
00695 && ( workspace()->activeClient() ==
this || this->hasTransient( workspace()->activeClient(),
true ))
00696 && raise_special_active_windows )
00697
return ActiveLayer;
00698
return NormalLayer;
00699 }
00700
00701 }