00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#include "group.h"
00021
00022
#include "workspace.h"
00023
#include "client.h"
00024
00025
#include <assert.h>
00026
#include <kstartupinfo.h>
00027
00028
00029
00030
00031
00032
00033
00034
00035
namespace KWinInternal
00036 {
00037
00038
00039
00040
00041
00042 Group::Group( Window leader_P, Workspace* workspace_P )
00043 : leader_client( NULL ),
00044 leader_wid( leader_P ),
00045 _workspace( workspace_P ),
00046 leader_info( NULL ),
00047 user_time( -1U )
00048 {
00049
if( leader_P != None )
00050 {
00051 leader_client = workspace_P->findClient( WindowMatchPredicate( leader_P ));
00052
unsigned long properties[ 2 ] = { 0, NET::WM2StartupId };
00053 leader_info =
new NETWinInfo( qt_xdisplay(), leader_P, workspace()->rootWin(),
00054 properties, 2 );
00055 }
00056 workspace()->addGroup(
this, Allowed );
00057 }
00058
00059 Group::~Group()
00060 {
00061
delete leader_info;
00062 }
00063
00064 QPixmap Group::icon()
const
00065
{
00066
if( leader_client != NULL )
00067
return leader_client->icon();
00068
else if( leader_wid != None )
00069 {
00070 QPixmap ic;
00071 Client::readIcons( leader_wid, &ic, NULL );
00072
return ic;
00073 }
00074
return QPixmap();
00075 }
00076
00077 QPixmap Group::miniIcon()
const
00078
{
00079
if( leader_client != NULL )
00080
return leader_client->miniIcon();
00081
else if( leader_wid != None )
00082 {
00083 QPixmap ic;
00084 Client::readIcons( leader_wid, NULL, &ic );
00085
return ic;
00086 }
00087
return QPixmap();
00088 }
00089
00090
void Group::addMember( Client* member_P )
00091 {
00092 _members.append( member_P );
00093
00094
00095 }
00096
00097
void Group::removeMember( Client* member_P )
00098 {
00099
00100
00101 Q_ASSERT( _members.contains( member_P ));
00102 _members.remove( member_P );
00103
if( _members.isEmpty())
00104 {
00105 workspace()->removeGroup(
this, Allowed );
00106
delete this;
00107 }
00108 }
00109
00110
void Group::gotLeader( Client* leader_P )
00111 {
00112 assert( leader_P->window() == leader_wid );
00113 leader_client = leader_P;
00114 }
00115
00116
void Group::lostLeader()
00117 {
00118 assert( !_members.contains( leader_client ));
00119 leader_client = NULL;
00120
if( _members.isEmpty())
00121 {
00122 workspace()->removeGroup(
this, Allowed );
00123
delete this;
00124 }
00125 }
00126
00127
void Group::getIcons()
00128 {
00129
00130 }
00131
00132
00133
00134
00135
00136 Group* Workspace::findGroup( Window leader )
const
00137
{
00138 assert( leader != None );
00139
for( GroupList::ConstIterator it = groups.begin();
00140 it != groups.end();
00141 ++it )
00142
if( (*it)->leader() == leader )
00143
return *it;
00144
return NULL;
00145 }
00146
00147
00148
00149 Group* Workspace::findClientLeaderGroup(
const Client* c )
const
00150
{
00151
for( ClientList::ConstIterator it = clients.begin();
00152 it != clients.end();
00153 ++it )
00154 {
00155
if( *it == c )
00156
continue;
00157
if( (*it)->wmClientLeader() == c->wmClientLeader())
00158
return (*it)->group();
00159 }
00160
return NULL;
00161 }
00162
00163
void Workspace::updateMinimizedOfTransients( Client* c )
00164 {
00165
00166
if ( c->isMinimized() || c->isShade() )
00167 {
00168
for( ClientList::ConstIterator it = c->transients().begin();
00169 it != c->transients().end();
00170 ++it )
00171 {
00172
if( !(*it)->isMinimized()
00173 && !(*it)->isShade()
00174 && !(*it)->isTopMenu() )
00175 {
00176 (*it)->minimize();
00177 updateMinimizedOfTransients( (*it) );
00178 }
00179 }
00180 }
00181
else
00182 {
00183
for( ClientList::ConstIterator it = c->transients().begin();
00184 it != c->transients().end();
00185 ++it )
00186 {
00187
if( (*it)->isMinimized()
00188 && !(*it)->isTopMenu())
00189 {
00190 (*it)->unminimize();
00191 updateMinimizedOfTransients( (*it) );
00192 }
00193 }
00194 }
00195 }
00196
00197
00201
void Workspace::updateOnAllDesktopsOfTransients( Client* c )
00202 {
00203
for( ClientList::ConstIterator it = c->transients().begin();
00204 it != c->transients().end();
00205 ++it)
00206 {
00207
if( (*it)->isOnAllDesktops() != c->isOnAllDesktops())
00208 (*it)->setOnAllDesktops( c->isOnAllDesktops());
00209 }
00210 }
00211
00212
00213
void Workspace::checkTransients( Window w )
00214 {
00215
for( ClientList::ConstIterator it = clients.begin();
00216 it != clients.end();
00217 ++it )
00218 (*it)->checkTransient( w );
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
bool Client::resourceMatch(
const Client* c1,
const Client* c2 )
00230 {
00231
00232
if( qstrncmp( c1->resourceClass(),
"xv", 2 ) == 0 && c1->resourceName() ==
"xv" )
00233
return qstrncmp( c2->resourceClass(),
"xv", 2 ) == 0 && c2->resourceName() ==
"xv";
00234
00235
if( c1->resourceName() ==
"mozilla" )
00236
return c2->resourceName() ==
"mozilla";
00237
return c1->resourceClass() == c2->resourceClass();
00238 }
00239
00240
bool Client::belongToSameApplication(
const Client* c1,
const Client* c2,
bool active_hack )
00241 {
00242
bool same_app =
false;
00243
if( c1 == c2 )
00244 same_app =
true;
00245
else if( c1->isTransient() && c2->hasTransient( c1,
true ))
00246 same_app =
true;
00247
else if( c2->isTransient() && c1->hasTransient( c2,
true ))
00248 same_app =
true;
00249
else if( c1->pid() != c2->pid()
00250 || c1->wmClientMachine() != c2->wmClientMachine())
00251 ;
00252
else if( c1->wmClientLeader() != c2->wmClientLeader()
00253 && c1->wmClientLeader() != c1->window()
00254 && c2->wmClientLeader() != c2->window())
00255 ;
00256
else if( !resourceMatch( c1, c2 ))
00257 ;
00258
else if( !sameAppWindowRoleMatch( c1, c2, active_hack ))
00259 ;
00260
else if( c1->wmClientLeader() == c2->wmClientLeader()
00261 && c1->wmClientLeader() != c1->window()
00262 && c2->wmClientLeader() != c2->window())
00263 same_app =
true;
00264
else if( c1->group() == c2->group())
00265 same_app =
true;
00266
else if( c1->pid() == 0 || c2->pid() == 0 )
00267 ;
00268
00269
else
00270 same_app =
true;
00271
return same_app;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
bool Client::sameAppWindowRoleMatch(
const Client* c1,
const Client* c2,
bool active_hack )
00285 {
00286
if( c1->isTransient())
00287 {
00288
while( c1->transientFor() != NULL )
00289 c1 = c1->transientFor();
00290
if( c1->groupTransient())
00291
return c1->group() == c2->group();
00292
#if 0
00293
00294
00295
00296 || c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
00297
#endif
00298
}
00299
if( c2->isTransient())
00300 {
00301
while( c2->transientFor() != NULL )
00302 c2 = c2->transientFor();
00303
if( c2->groupTransient())
00304
return c1->group() == c2->group();
00305
#if 0
00306
|| c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
00307
#endif
00308
}
00309
int pos1 = c1->windowRole().find(
'#' );
00310
int pos2 = c2->windowRole().find(
'#' );
00311
if(( pos1 >= 0 && pos2 >= 0 )
00312 ||
00313
00314
00315 c1->resourceName() ==
"mozilla" && c2->resourceName() ==
"mozilla" )
00316 {
00317
if( !active_hack )
00318
return c1 == c2;
00319
if( !c1->isActive() && !c2->isActive())
00320
return c1 == c2;
00321
else
00322
return true;
00323 }
00324
return true;
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
void Client::readTransient()
00374 {
00375 Window new_transient_for_id;
00376
if( XGetTransientForHint( qt_xdisplay(), window(), &new_transient_for_id ))
00377 {
00378 original_transient_for_id = new_transient_for_id;
00379 new_transient_for_id = verifyTransientFor( new_transient_for_id,
true );
00380 }
00381
else
00382 {
00383 original_transient_for_id = None;
00384 new_transient_for_id = verifyTransientFor( None,
false );
00385 }
00386 setTransient( new_transient_for_id );
00387 }
00388
00389
void Client::setTransient( Window new_transient_for_id )
00390 {
00391
if( new_transient_for_id != transient_for_id )
00392 {
00393 removeFromMainClients();
00394 transient_for = NULL;
00395 transient_for_id = new_transient_for_id;
00396
if( transient_for_id != None && !groupTransient())
00397 {
00398 transient_for = workspace()->findClient( WindowMatchPredicate( transient_for_id ));
00399 assert( transient_for != NULL );
00400 transient_for->addTransient(
this );
00401 }
00402 checkGroup();
00403
if( groupTransient())
00404 {
00405
for( ClientList::ConstIterator it = group()->members().begin();
00406 it != group()->members().end();
00407 ++it )
00408 {
00409
if( *it ==
this )
00410
break;
00411 (*it)->addTransient(
this );
00412 }
00413 }
00414 checkGroupTransients();
00415 workspace()->updateClientLayer(
this );
00416 }
00417 }
00418
00419
void Client::removeFromMainClients()
00420 {
00421
if( transientFor() != NULL )
00422 transientFor()->removeTransient(
this );
00423
if( groupTransient())
00424 {
00425
for( ClientList::ConstIterator it = group()->members().begin();
00426 it != group()->members().end();
00427 ++it )
00428 (*it)->removeTransient(
this );
00429 }
00430 }
00431
00432
00433
00434
00435
00436
void Client::cleanGrouping()
00437 {
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449 removeFromMainClients();
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
for( ClientList::ConstIterator it = transients_list.begin();
00461 it != transients_list.end();
00462 )
00463 {
00464
if( (*it)->transientFor() ==
this )
00465 {
00466 ClientList::ConstIterator it2 = it++;
00467 removeTransient( *it2 );
00468 }
00469
else
00470 ++it;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 ClientList group_members = group()->members();
00488 group()->removeMember(
this );
00489 in_group = NULL;
00490
for( ClientList::ConstIterator it = group_members.begin();
00491 it != group_members.end();
00492 ++it )
00493 (*it)->removeTransient(
this );
00494
00495
00496
00497
00498
00499 }
00500
00501
00502
00503
00504
00505
void Client::checkGroupTransients()
00506 {
00507
for( ClientList::ConstIterator it1 = group()->members().begin();
00508 it1 != group()->members().end();
00509 ++it1 )
00510 {
00511
if( !(*it1)->groupTransient())
00512
continue;
00513
for( ClientList::ConstIterator it2 = group()->members().begin();
00514 it2 != group()->members().end();
00515 ++it2 )
00516 {
00517
if( *it1 == *it2 )
00518
continue;
00519
for(
Client* cl = (*it2)->transientFor();
00520 cl != NULL;
00521 cl = cl->transientFor())
00522 {
00523
if( cl == *it1 )
00524 {
00525 (*it2)->transients_list.remove( *it1 );
00526
continue;
00527 }
00528 }
00529
00530
00531
00532
00533
if( (*it2)->groupTransient() && (*it1)->hasTransient( *it2,
true ) && (*it2)->hasTransient( *it1,
true ))
00534 (*it2)->transients_list.remove( *it1 );
00535 }
00536 }
00537 }
00538
00542 Window Client::verifyTransientFor( Window new_transient_for,
bool defined )
00543 {
00544 Window new_property_value = new_transient_for;
00545
00546
00547
if( isSplash() && new_transient_for == None )
00548 new_transient_for = workspace()->rootWin();
00549
if( new_transient_for == None )
00550
if( defined )
00551 new_property_value = new_transient_for = workspace()->rootWin();
00552
else
00553
return None;
00554
if( new_transient_for == window())
00555 {
00556 kdWarning( 1216 ) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to itself." << endl;
00557 new_property_value = new_transient_for = workspace()->rootWin();
00558 }
00559
00560
00561
00562 WId before_search = new_transient_for;
00563
while( new_transient_for != None
00564 && new_transient_for != workspace()->rootWin()
00565 && !workspace()->findClient( WindowMatchPredicate( new_transient_for )))
00566 {
00567 Window root_return, parent_return;
00568 Window* wins = NULL;
00569
unsigned int nwins;
00570
int r = XQueryTree(qt_xdisplay(), new_transient_for, &root_return, &parent_return, &wins, &nwins);
00571
if ( wins )
00572 XFree((
void *) wins);
00573
if ( r == 0)
00574
break;
00575 new_transient_for = parent_return;
00576 }
00577
if(
Client* new_transient_for_client = workspace()->findClient( WindowMatchPredicate( new_transient_for )))
00578 {
00579
if( new_transient_for != before_search )
00580 {
00581 kdDebug( 1212 ) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to non-toplevel window "
00582 << before_search <<
", child of " << new_transient_for_client <<
", adjusting." << endl;
00583 new_property_value = new_transient_for;
00584 }
00585 }
00586
else
00587 new_transient_for = before_search;
00588
00589
00590
00591
int count = 20;
00592 Window loop_pos = new_transient_for;
00593
while( loop_pos != None && loop_pos != workspace()->rootWin())
00594 {
00595
Client* pos = workspace()->findClient( WindowMatchPredicate( loop_pos ));
00596
if( pos == NULL )
00597
break;
00598 loop_pos = pos->transient_for_id;
00599
if( --count == 0 )
00600 {
00601 kdWarning( 1216 ) <<
"Client " <<
this <<
" caused WM_TRANSIENT_FOR loop." << endl;
00602 new_transient_for = workspace()->rootWin();
00603 }
00604 }
00605
if( new_transient_for != workspace()->rootWin()
00606 && workspace()->findClient( WindowMatchPredicate( new_transient_for )) == NULL )
00607 {
00608 new_transient_for = workspace()->rootWin();
00609 }
00610
if( new_property_value != original_transient_for_id )
00611 XSetTransientForHint( qt_xdisplay(), window(), new_property_value );
00612
return new_transient_for;
00613 }
00614
00615
void Client::addTransient( Client* cl )
00616 {
00617 assert( !transients_list.contains( cl ));
00618
00619 assert( cl !=
this );
00620 transients_list.append( cl );
00621
if( workspace()->mostRecentlyActivatedClient() ==
this && cl->isModal())
00622 workspace()->activateClient( findModal());
00623
00624
00625
00626
00627
00628
00629 }
00630
00631
void Client::removeTransient( Client* cl )
00632 {
00633
00634
00635 transients_list.remove( cl );
00636
00637
00638
if( cl->transientFor() ==
this )
00639 {
00640 cl->transient_for_id = None;
00641 cl->transient_for = NULL;
00642
00643 cl->setTransient( None );
00644 }
00645 }
00646
00647
00648
void Client::checkTransient( Window w )
00649 {
00650
if( original_transient_for_id != w )
00651
return;
00652 w = verifyTransientFor( w,
true );
00653 setTransient( w );
00654 }
00655
00656
00657
00658
bool Client::hasTransient(
const Client* cl,
bool indirect )
const
00659
{
00660
00661 ConstClientList set;
00662
return hasTransientInternal( cl, indirect, set );
00663 }
00664
00665
bool Client::hasTransientInternal(
const Client* cl,
bool indirect, ConstClientList& set )
const
00666
{
00667
if( set.contains(
this ))
00668
return false;
00669 set.append(
this );
00670
if( cl->transientFor() != NULL )
00671 {
00672
if( cl->transientFor() ==
this )
00673
return true;
00674
if( !indirect )
00675
return false;
00676
return hasTransientInternal( cl->transientFor(), indirect, set );
00677 }
00678
if( !cl->isTransient())
00679
return false;
00680
if( group() != cl->group())
00681
return false;
00682
00683
if( transients().contains( const_cast< Client* >( cl )))
00684
return true;
00685
if( !indirect )
00686
return false;
00687
for( ClientList::ConstIterator it = transients().begin();
00688 it != transients().end();
00689 ++it )
00690
if( (*it)->hasTransientInternal( cl, indirect, set ))
00691
return true;
00692
return false;
00693 }
00694
00695 ClientList Client::mainClients()
const
00696
{
00697
if( !isTransient())
00698
return ClientList();
00699
if( transientFor() != NULL )
00700
return ClientList() << const_cast< Client* >( transientFor());
00701 ClientList result;
00702
for( ClientList::ConstIterator it = group()->members().begin();
00703 it != group()->members().end();
00704 ++it )
00705
if((*it)->hasTransient(
this,
false ))
00706 result.append( *it );
00707
return result;
00708 }
00709
00710 Client* Client::findModal()
00711 {
00712
for( ClientList::ConstIterator it = transients().begin();
00713 it != transients().end();
00714 ++it )
00715
if(
Client* ret = (*it)->findModal())
00716
return ret;
00717
if( isModal())
00718
return this;
00719
return NULL;
00720 }
00721
00722
00723
00724
void Client::checkGroup()
00725 {
00726 Group* old_group = in_group;
00727
if( window_group != None )
00728 {
00729 Group* new_group = workspace()->findGroup( window_group );
00730
if( transientFor() != NULL && transientFor()->group() != new_group )
00731 {
00732
00733 new_group = transientFor()->group();
00734 }
00735
if( new_group == NULL )
00736 new_group =
new Group( window_group, workspace());
00737
if( new_group != in_group )
00738 {
00739
if( in_group != NULL )
00740 in_group->removeMember(
this );
00741 in_group = new_group;
00742 in_group->addMember(
this );
00743 }
00744 }
00745
else
00746 {
00747
if( transientFor() != NULL )
00748 {
00749
00750 Group* new_group = transientFor()->group();
00751
if( new_group != in_group )
00752 {
00753
if( in_group != NULL )
00754 in_group->removeMember(
this );
00755 in_group = transientFor()->group();
00756 in_group->addMember(
this );
00757 }
00758 }
00759
else if( groupTransient())
00760 {
00761
00762 Group* new_group = workspace()->findClientLeaderGroup(
this );
00763
if( new_group == NULL )
00764 new_group =
new Group( None, workspace());
00765
if( new_group != in_group )
00766 {
00767
if( in_group != NULL )
00768 in_group->removeMember(
this );
00769 in_group = new_group;
00770 in_group->addMember(
this );
00771 }
00772 }
00773
else
00774 {
00775
if( in_group != NULL && in_group->leader() != window())
00776 {
00777 in_group->removeMember(
this );
00778 in_group = NULL;
00779 }
00780
if( in_group == NULL )
00781 {
00782 in_group =
new Group( None, workspace());
00783 in_group->addMember(
this );
00784 }
00785 }
00786 }
00787
if( in_group != old_group )
00788 {
00789
for( ClientList::Iterator it = transients_list.begin();
00790 it != transients_list.end();
00791 )
00792 {
00793
if( (*it)->groupTransient() && (*it)->group() != group())
00794 it = transients_list.remove( it );
00795
else
00796 ++it;
00797 }
00798
#if 0 // TODO
00799
if( groupTransient())
00800 {
00801
if( workspace()->findGroup( old_group ))
00802 {
00803
for( ClientList::ConstIterator it = old_group->members().begin();
00804 it != old_group->members().end();
00805 ++it )
00806 (*it)->removeTransient(
this );
00807 }
00808
00809
00810
00811
for( ClientList::ConstIterator it = group()->members().begin();
00812 it != group()->members().end();
00813 ++it )
00814 (*it)->addTransient(
this );
00815 }
00816
#endif
00817
#if 0 // this would make group transients transient for window that were mapped later
00818
for( ClientList::ConstIterator it = group()->members().begin();
00819 it != group()->members().end();
00820 ++it )
00821 {
00822
if( !(*it)->groupTransient())
00823
continue;
00824
if( *it ==
this )
00825
continue;
00826 addTransient( *it );
00827 }
00828 checkGroupTransients();
00829
#endif
00830
}
00831 }
00832
00833
00834 }