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 Group* ret = NULL;
00152
for( ClientList::ConstIterator it = clients.begin();
00153 it != clients.end();
00154 ++it )
00155 {
00156
if( *it == c )
00157
continue;
00158
if( (*it)->wmClientLeader() == c->wmClientLeader())
00159 {
00160
if( ret == NULL || ret == (*it)->group())
00161 ret = (*it)->group();
00162
else
00163 {
00164
00165
00166
00167
00168 Group* old_group = (*it)->group();
00169
00170
for(
int cnt = old_group->members().count();
00171 cnt > 0;
00172 --cnt )
00173 {
00174
Client* tmp = old_group->members().first();
00175 tmp->checkGroup( ret );
00176 }
00177 }
00178 }
00179 }
00180
return ret;
00181 }
00182
00183
void Workspace::updateMinimizedOfTransients( Client* c )
00184 {
00185
00186
if ( c->isMinimized() || c->isShade() )
00187 {
00188
for( ClientList::ConstIterator it = c->transients().begin();
00189 it != c->transients().end();
00190 ++it )
00191 {
00192
if( !(*it)->isMinimized()
00193 && !(*it)->isTopMenu() )
00194 {
00195 (*it)->minimize(
true );
00196 updateMinimizedOfTransients( (*it) );
00197 }
00198 }
00199 }
00200
else
00201 {
00202
for( ClientList::ConstIterator it = c->transients().begin();
00203 it != c->transients().end();
00204 ++it )
00205 {
00206
if( (*it)->isMinimized()
00207 && !(*it)->isTopMenu())
00208 {
00209 (*it)->unminimize(
true );
00210 updateMinimizedOfTransients( (*it) );
00211 }
00212 }
00213 }
00214 }
00215
00216
00220
void Workspace::updateOnAllDesktopsOfTransients( Client* c )
00221 {
00222
for( ClientList::ConstIterator it = c->transients().begin();
00223 it != c->transients().end();
00224 ++it)
00225 {
00226
if( (*it)->isOnAllDesktops() != c->isOnAllDesktops())
00227 (*it)->setOnAllDesktops( c->isOnAllDesktops());
00228 }
00229 }
00230
00231
00232
void Workspace::checkTransients( Window w )
00233 {
00234
for( ClientList::ConstIterator it = clients.begin();
00235 it != clients.end();
00236 ++it )
00237 (*it)->checkTransient( w );
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
bool Client::resourceMatch(
const Client* c1,
const Client* c2 )
00249 {
00250
00251
if( qstrncmp( c1->resourceClass(),
"xv", 2 ) == 0 && c1->resourceName() ==
"xv" )
00252
return qstrncmp( c2->resourceClass(),
"xv", 2 ) == 0 && c2->resourceName() ==
"xv";
00253
00254
if( c1->resourceName() ==
"mozilla" )
00255
return c2->resourceName() ==
"mozilla";
00256
return c1->resourceClass() == c2->resourceClass();
00257 }
00258
00259
bool Client::belongToSameApplication(
const Client* c1,
const Client* c2,
bool active_hack )
00260 {
00261
bool same_app =
false;
00262
if( c1 == c2 )
00263 same_app =
true;
00264
else if( c1->isTransient() && c2->hasTransient( c1,
true ))
00265 same_app =
true;
00266
else if( c2->isTransient() && c1->hasTransient( c2,
true ))
00267 same_app =
true;
00268
else if( c1->pid() != c2->pid()
00269 || c1->wmClientMachine(
false ) != c2->wmClientMachine(
false ))
00270 ;
00271
else if( c1->wmClientLeader() != c2->wmClientLeader()
00272 && c1->wmClientLeader() != c1->window()
00273 && c2->wmClientLeader() != c2->window())
00274 ;
00275
else if( !resourceMatch( c1, c2 ))
00276 ;
00277
else if( !sameAppWindowRoleMatch( c1, c2, active_hack ))
00278 ;
00279
else if( c1->wmClientLeader() == c2->wmClientLeader()
00280 && c1->wmClientLeader() != c1->window()
00281 && c2->wmClientLeader() != c2->window())
00282 same_app =
true;
00283
else if( c1->group() == c2->group())
00284 same_app =
true;
00285
else if( c1->pid() == 0 || c2->pid() == 0 )
00286 ;
00287
00288
else
00289 same_app =
true;
00290
return same_app;
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
bool Client::sameAppWindowRoleMatch(
const Client* c1,
const Client* c2,
bool active_hack )
00304 {
00305
if( c1->isTransient())
00306 {
00307
while( c1->transientFor() != NULL )
00308 c1 = c1->transientFor();
00309
if( c1->groupTransient())
00310
return c1->group() == c2->group();
00311
#if 0
00312
00313
00314
00315 || c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
00316
#endif
00317
}
00318
if( c2->isTransient())
00319 {
00320
while( c2->transientFor() != NULL )
00321 c2 = c2->transientFor();
00322
if( c2->groupTransient())
00323
return c1->group() == c2->group();
00324
#if 0
00325
|| c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
00326
#endif
00327
}
00328
int pos1 = c1->windowRole().find(
'#' );
00329
int pos2 = c2->windowRole().find(
'#' );
00330
if(( pos1 >= 0 && pos2 >= 0 )
00331 ||
00332
00333
00334 c1->resourceName() ==
"mozilla" && c2->resourceName() ==
"mozilla" )
00335 {
00336
if( !active_hack )
00337
return c1 == c2;
00338
if( !c1->isActive() && !c2->isActive())
00339
return c1 == c2;
00340
else
00341
return true;
00342 }
00343
return true;
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
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
void Client::readTransient()
00393 {
00394 Window new_transient_for_id;
00395
if( XGetTransientForHint( qt_xdisplay(), window(), &new_transient_for_id ))
00396 {
00397 original_transient_for_id = new_transient_for_id;
00398 new_transient_for_id = verifyTransientFor( new_transient_for_id,
true );
00399 }
00400
else
00401 {
00402 original_transient_for_id = None;
00403 new_transient_for_id = verifyTransientFor( None,
false );
00404 }
00405 setTransient( new_transient_for_id );
00406 }
00407
00408
void Client::setTransient( Window new_transient_for_id )
00409 {
00410
if( new_transient_for_id != transient_for_id )
00411 {
00412 removeFromMainClients();
00413 transient_for = NULL;
00414 transient_for_id = new_transient_for_id;
00415
if( transient_for_id != None && !groupTransient())
00416 {
00417 transient_for = workspace()->findClient( WindowMatchPredicate( transient_for_id ));
00418 assert( transient_for != NULL );
00419 transient_for->addTransient(
this );
00420 }
00421 checkGroup( NULL,
true );
00422
if( isTopMenu())
00423 workspace()->updateCurrentTopMenu();
00424 workspace()->updateClientLayer(
this );
00425 }
00426 }
00427
00428
void Client::removeFromMainClients()
00429 {
00430
if( transientFor() != NULL )
00431 transientFor()->removeTransient(
this );
00432
if( groupTransient())
00433 {
00434
for( ClientList::ConstIterator it = group()->members().begin();
00435 it != group()->members().end();
00436 ++it )
00437 (*it)->removeTransient(
this );
00438 }
00439 }
00440
00441
00442
00443
00444
00445
void Client::cleanGrouping()
00446 {
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 removeFromMainClients();
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
for( ClientList::ConstIterator it = transients_list.begin();
00470 it != transients_list.end();
00471 )
00472 {
00473
if( (*it)->transientFor() ==
this )
00474 {
00475 ClientList::ConstIterator it2 = it++;
00476 removeTransient( *it2 );
00477 }
00478
else
00479 ++it;
00480 }
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 ClientList group_members = group()->members();
00497 group()->removeMember(
this );
00498 in_group = NULL;
00499
for( ClientList::ConstIterator it = group_members.begin();
00500 it != group_members.end();
00501 ++it )
00502 (*it)->removeTransient(
this );
00503
00504
00505
00506
00507
00508 }
00509
00510
00511
00512
00513
00514
void Client::checkGroupTransients()
00515 {
00516
for( ClientList::ConstIterator it1 = group()->members().begin();
00517 it1 != group()->members().end();
00518 ++it1 )
00519 {
00520
if( !(*it1)->groupTransient())
00521
continue;
00522
for( ClientList::ConstIterator it2 = group()->members().begin();
00523 it2 != group()->members().end();
00524 ++it2 )
00525 {
00526
if( *it1 == *it2 )
00527
continue;
00528
for(
Client* cl = (*it2)->transientFor();
00529 cl != NULL;
00530 cl = cl->transientFor())
00531 {
00532
if( cl == *it1 )
00533 {
00534 (*it2)->transients_list.remove( *it1 );
00535
continue;
00536 }
00537 }
00538
00539
00540
00541
00542
if( (*it2)->groupTransient() && (*it1)->hasTransient( *it2,
true ) && (*it2)->hasTransient( *it1,
true ))
00543 (*it2)->transients_list.remove( *it1 );
00544 }
00545 }
00546 }
00547
00551 Window Client::verifyTransientFor( Window new_transient_for,
bool defined )
00552 {
00553 Window new_property_value = new_transient_for;
00554
00555
00556
if( isSplash() && new_transient_for == None )
00557 new_transient_for = workspace()->rootWin();
00558
if( new_transient_for == None )
00559
if( defined )
00560 new_property_value = new_transient_for = workspace()->rootWin();
00561
else
00562
return None;
00563
if( new_transient_for == window())
00564 {
00565 kdWarning( 1216 ) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to itself." << endl;
00566 new_property_value = new_transient_for = workspace()->rootWin();
00567 }
00568
00569
00570
00571 WId before_search = new_transient_for;
00572
while( new_transient_for != None
00573 && new_transient_for != workspace()->rootWin()
00574 && !workspace()->findClient( WindowMatchPredicate( new_transient_for )))
00575 {
00576 Window root_return, parent_return;
00577 Window* wins = NULL;
00578
unsigned int nwins;
00579
int r = XQueryTree(qt_xdisplay(), new_transient_for, &root_return, &parent_return, &wins, &nwins);
00580
if ( wins )
00581 XFree((
void *) wins);
00582
if ( r == 0)
00583
break;
00584 new_transient_for = parent_return;
00585 }
00586
if(
Client* new_transient_for_client = workspace()->findClient( WindowMatchPredicate( new_transient_for )))
00587 {
00588
if( new_transient_for != before_search )
00589 {
00590 kdDebug( 1212 ) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to non-toplevel window "
00591 << before_search <<
", child of " << new_transient_for_client <<
", adjusting." << endl;
00592 new_property_value = new_transient_for;
00593 }
00594 }
00595
else
00596 new_transient_for = before_search;
00597
00598
00599
00600
int count = 20;
00601 Window loop_pos = new_transient_for;
00602
while( loop_pos != None && loop_pos != workspace()->rootWin())
00603 {
00604
Client* pos = workspace()->findClient( WindowMatchPredicate( loop_pos ));
00605
if( pos == NULL )
00606
break;
00607 loop_pos = pos->transient_for_id;
00608
if( --count == 0 )
00609 {
00610 kdWarning( 1216 ) <<
"Client " <<
this <<
" caused WM_TRANSIENT_FOR loop." << endl;
00611 new_transient_for = workspace()->rootWin();
00612 }
00613 }
00614
if( new_transient_for != workspace()->rootWin()
00615 && workspace()->findClient( WindowMatchPredicate( new_transient_for )) == NULL )
00616 {
00617 new_transient_for = workspace()->rootWin();
00618 }
00619
if( new_property_value != original_transient_for_id )
00620 XSetTransientForHint( qt_xdisplay(), window(), new_property_value );
00621
return new_transient_for;
00622 }
00623
00624
void Client::addTransient( Client* cl )
00625 {
00626 assert( !transients_list.contains( cl ));
00627
00628 assert( cl !=
this );
00629 transients_list.append( cl );
00630
if( workspace()->mostRecentlyActivatedClient() ==
this && cl->isModal())
00631 check_active_modal =
true;
00632
00633
00634
00635
00636
00637
00638 }
00639
00640
void Client::removeTransient( Client* cl )
00641 {
00642
00643
00644 transients_list.remove( cl );
00645
00646
00647
if( cl->transientFor() ==
this )
00648 {
00649 cl->transient_for_id = None;
00650 cl->transient_for = NULL;
00651
00652 cl->setTransient( None );
00653 }
00654 }
00655
00656
00657
void Client::checkTransient( Window w )
00658 {
00659
if( original_transient_for_id != w )
00660
return;
00661 w = verifyTransientFor( w,
true );
00662 setTransient( w );
00663 }
00664
00665
00666
00667
bool Client::hasTransient(
const Client* cl,
bool indirect )
const
00668
{
00669
00670 ConstClientList set;
00671
return hasTransientInternal( cl, indirect, set );
00672 }
00673
00674
bool Client::hasTransientInternal(
const Client* cl,
bool indirect, ConstClientList& set )
const
00675
{
00676
if( set.contains(
this ))
00677
return false;
00678 set.append(
this );
00679
if( cl->transientFor() != NULL )
00680 {
00681
if( cl->transientFor() ==
this )
00682
return true;
00683
if( !indirect )
00684
return false;
00685
return hasTransientInternal( cl->transientFor(), indirect, set );
00686 }
00687
if( !cl->isTransient())
00688
return false;
00689
if( group() != cl->group())
00690
return false;
00691
00692
if( transients().contains( const_cast< Client* >( cl )))
00693
return true;
00694
if( !indirect )
00695
return false;
00696
for( ClientList::ConstIterator it = transients().begin();
00697 it != transients().end();
00698 ++it )
00699
if( (*it)->hasTransientInternal( cl, indirect, set ))
00700
return true;
00701
return false;
00702 }
00703
00704 ClientList Client::mainClients()
const
00705
{
00706
if( !isTransient())
00707
return ClientList();
00708
if( transientFor() != NULL )
00709
return ClientList() << const_cast< Client* >( transientFor());
00710 ClientList result;
00711
for( ClientList::ConstIterator it = group()->members().begin();
00712 it != group()->members().end();
00713 ++it )
00714
if((*it)->hasTransient(
this,
false ))
00715 result.append( *it );
00716
return result;
00717 }
00718
00719 Client* Client::findModal()
00720 {
00721
for( ClientList::ConstIterator it = transients().begin();
00722 it != transients().end();
00723 ++it )
00724
if(
Client* ret = (*it)->findModal())
00725
return ret;
00726
if( isModal())
00727
return this;
00728
return NULL;
00729 }
00730
00731
00732
00733
00734
void Client::checkGroup( Group* set_group,
bool force )
00735 {
00736 Group* old_group = in_group;
00737
if( set_group != NULL )
00738 {
00739
if( set_group != in_group )
00740 {
00741
if( in_group != NULL )
00742 in_group->removeMember(
this );
00743 in_group = set_group;
00744 in_group->addMember(
this );
00745 }
00746 }
00747
else if( window_group != None )
00748 {
00749 Group* new_group = workspace()->findGroup( window_group );
00750
if( transientFor() != NULL && transientFor()->group() != new_group )
00751 {
00752
00753 new_group = transientFor()->group();
00754 }
00755
if( new_group == NULL )
00756 new_group =
new Group( window_group, workspace());
00757
if( new_group != in_group )
00758 {
00759
if( in_group != NULL )
00760 in_group->removeMember(
this );
00761 in_group = new_group;
00762 in_group->addMember(
this );
00763 }
00764 }
00765
else
00766 {
00767
if( transientFor() != NULL )
00768 {
00769
00770 Group* new_group = transientFor()->group();
00771
if( new_group != in_group )
00772 {
00773
if( in_group != NULL )
00774 in_group->removeMember(
this );
00775 in_group = transientFor()->group();
00776 in_group->addMember(
this );
00777 }
00778 }
00779
else if( groupTransient())
00780 {
00781
00782 Group* new_group = workspace()->findClientLeaderGroup(
this );
00783
if( new_group == NULL )
00784 new_group =
new Group( None, workspace());
00785
if( new_group != in_group )
00786 {
00787
if( in_group != NULL )
00788 in_group->removeMember(
this );
00789 in_group = new_group;
00790 in_group->addMember(
this );
00791 }
00792 }
00793
else
00794 {
00795
if( in_group != NULL && in_group->leader() != window())
00796 {
00797 in_group->removeMember(
this );
00798 in_group = NULL;
00799 }
00800
if( in_group == NULL )
00801 {
00802 in_group =
new Group( None, workspace());
00803 in_group->addMember(
this );
00804 }
00805 }
00806 }
00807
if( in_group != old_group || force )
00808 {
00809
for( ClientList::Iterator it = transients_list.begin();
00810 it != transients_list.end();
00811 )
00812 {
00813
if( (*it)->groupTransient() && (*it)->group() != group())
00814 it = transients_list.remove( it );
00815
else
00816 ++it;
00817 }
00818
if( groupTransient())
00819 {
00820
for( ClientList::ConstIterator it = group()->members().begin();
00821 it != group()->members().end();
00822 ++it )
00823 {
00824
if( *it ==
this )
00825
break;
00826 (*it)->addTransient(
this );
00827 }
00828 }
00829
#if 0 // TODO
00830
if( groupTransient())
00831 {
00832
if( workspace()->findGroup( old_group ))
00833 {
00834
for( ClientList::ConstIterator it = old_group->members().begin();
00835 it != old_group->members().end();
00836 ++it )
00837 (*it)->removeTransient(
this );
00838 }
00839
00840
00841
00842
for( ClientList::ConstIterator it = group()->members().begin();
00843 it != group()->members().end();
00844 ++it )
00845 (*it)->addTransient(
this );
00846 }
00847
#endif
00848
00849
00850
for( ClientList::ConstIterator it = group()->members().begin();
00851 it != group()->members().end();
00852 ++it )
00853 {
00854
if( !(*it)->isSplash())
00855
continue;
00856
if( !(*it)->groupTransient())
00857
continue;
00858
if( *it ==
this || hasTransient( *it,
true ))
00859
continue;
00860 addTransient( *it );
00861 }
00862 }
00863 checkGroupTransients();
00864 checkActiveModal();
00865 workspace()->updateClientLayer(
this );
00866 }
00867
00868
bool Client::check_active_modal =
false;
00869
00870
void Client::checkActiveModal()
00871 {
00872
00873
00874
00875
Client* check_modal = workspace()->mostRecentlyActivatedClient();
00876
if( check_modal != NULL && check_modal->check_active_modal )
00877 {
00878
Client* new_modal = check_modal->findModal();
00879
if( new_modal != NULL && new_modal != check_modal )
00880 {
00881
if( !new_modal->isManaged())
00882
return;
00883 workspace()->activateClient( new_modal );
00884 }
00885 check_modal->check_active_modal =
false;
00886 }
00887 }
00888
00889 }