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
00043
00044
00045 #ifdef NDEBUG
00046 #undef ENABLE_TRANSIENCY_CHECK
00047 #endif
00048
00049 #ifdef ENABLE_TRANSIENCY_CHECK
00050 static bool transiencyCheckNonExistent = false;
00051
00052 bool performTransiencyCheck()
00053 {
00054 bool ret = true;
00055 ClientList clients = Workspace::self()->clients;
00056 for( ClientList::ConstIterator it1 = clients.begin();
00057 it1 != clients.end();
00058 ++it1 )
00059 {
00060 if( (*it1)->deleting )
00061 continue;
00062 if( (*it1)->in_group == NULL )
00063 {
00064 kdDebug() << "TC: " << *it1 << " in not in a group" << endl;
00065 ret = false;
00066 }
00067 else if( !(*it1)->in_group->members().contains( *it1 ))
00068 {
00069 kdDebug() << "TC: " << *it1 << " has a group " << (*it1)->in_group << " but group does not contain it" << endl;
00070 ret = false;
00071 }
00072 if( !(*it1)->isTransient())
00073 {
00074 if( !(*it1)->mainClients().isEmpty())
00075 {
00076 kdDebug() << "TC: " << *it1 << " is not transient, has main clients:" << (*it1)->mainClients() << endl;
00077 ret = false;
00078 }
00079 }
00080 else
00081 {
00082 ClientList mains = (*it1)->mainClients();
00083 for( ClientList::ConstIterator it2 = mains.begin();
00084 it2 != mains.end();
00085 ++it2 )
00086 {
00087 if( transiencyCheckNonExistent
00088 && !Workspace::self()->clients.contains( *it2 )
00089 && !Workspace::self()->desktops.contains( *it2 ))
00090 {
00091 kdDebug() << "TC:" << *it1 << " has non-existent main client " << endl;
00092 kdDebug() << "TC2:" << *it2 << endl;
00093 ret = false;
00094 continue;
00095 }
00096 if( !(*it2)->transients_list.contains( *it1 ))
00097 {
00098 kdDebug() << "TC:" << *it1 << " has main client " << *it2 << " but main client does not have it as a transient" << endl;
00099 ret = false;
00100 }
00101 }
00102 }
00103 ClientList trans = (*it1)->transients_list;
00104 for( ClientList::ConstIterator it2 = trans.begin();
00105 it2 != trans.end();
00106 ++it2 )
00107 {
00108 if( transiencyCheckNonExistent
00109 && !Workspace::self()->clients.contains( *it2 )
00110 && !Workspace::self()->desktops.contains( *it2 ))
00111 {
00112 kdDebug() << "TC:" << *it1 << " has non-existent transient " << endl;
00113 kdDebug() << "TC2:" << *it2 << endl;
00114 ret = false;
00115 continue;
00116 }
00117 if( !(*it2)->mainClients().contains( *it1 ))
00118 {
00119 kdDebug() << "TC:" << *it1 << " has transient " << *it2 << " but transient does not have it as a main client" << endl;
00120 ret = false;
00121 }
00122 }
00123 }
00124 GroupList groups = Workspace::self()->groups;
00125 for( GroupList::ConstIterator it1 = groups.begin();
00126 it1 != groups.end();
00127 ++it1 )
00128 {
00129 ClientList members = (*it1)->members();
00130 for( ClientList::ConstIterator it2 = members.begin();
00131 it2 != members.end();
00132 ++it2 )
00133 {
00134 if( (*it2)->in_group != *it1 )
00135 {
00136 kdDebug() << "TC: Group " << *it1 << " contains client " << *it2 << " but client is not in that group" << endl;
00137 ret = false;
00138 }
00139 }
00140 }
00141 return ret;
00142 }
00143
00144 static QString transiencyCheckStartBt;
00145 static const Client* transiencyCheckClient;
00146 static int transiencyCheck = 0;
00147
00148 static void startTransiencyCheck( const QString& bt, const Client* c, bool ne )
00149 {
00150 if( ++transiencyCheck == 1 )
00151 {
00152 transiencyCheckStartBt = bt;
00153 transiencyCheckClient = c;
00154 }
00155 if( ne )
00156 transiencyCheckNonExistent = true;
00157 }
00158 static void checkTransiency()
00159 {
00160 if( --transiencyCheck == 0 )
00161 {
00162 if( !performTransiencyCheck())
00163 {
00164 kdDebug() << "BT:" << transiencyCheckStartBt << endl;
00165 kdDebug() << "CLIENT:" << transiencyCheckClient << endl;
00166 assert( false );
00167 }
00168 transiencyCheckNonExistent = false;
00169 }
00170 }
00171 class TransiencyChecker
00172 {
00173 public:
00174 TransiencyChecker( const QString& bt, const Client*c ) { startTransiencyCheck( bt, c, false ); }
00175 ~TransiencyChecker() { checkTransiency(); }
00176 };
00177
00178 void checkNonExistentClients()
00179 {
00180 startTransiencyCheck( kdBacktrace(), NULL, true );
00181 checkTransiency();
00182 }
00183
00184 #define TRANSIENCY_CHECK( c ) TransiencyChecker transiency_checker( kdBacktrace(), c )
00185
00186 #else
00187
00188 #define TRANSIENCY_CHECK( c )
00189
00190 void checkNonExistentClients()
00191 {
00192 }
00193
00194 #endif
00195
00196
00197
00198
00199
00200 Group::Group( Window leader_P, Workspace* workspace_P )
00201 : leader_client( NULL ),
00202 leader_wid( leader_P ),
00203 _workspace( workspace_P ),
00204 leader_info( NULL ),
00205 user_time( -1U ),
00206 refcount( 0 )
00207 {
00208 if( leader_P != None )
00209 {
00210 leader_client = workspace_P->findClient( WindowMatchPredicate( leader_P ));
00211 unsigned long properties[ 2 ] = { 0, NET::WM2StartupId };
00212 leader_info = new NETWinInfo( qt_xdisplay(), leader_P, workspace()->rootWin(),
00213 properties, 2 );
00214 }
00215 workspace()->addGroup( this, Allowed );
00216 }
00217
00218 Group::~Group()
00219 {
00220 delete leader_info;
00221 }
00222
00223 QPixmap Group::icon() const
00224 {
00225 if( leader_client != NULL )
00226 return leader_client->icon();
00227 else if( leader_wid != None )
00228 {
00229 QPixmap ic;
00230 Client::readIcons( leader_wid, &ic, NULL );
00231 return ic;
00232 }
00233 return QPixmap();
00234 }
00235
00236 QPixmap Group::miniIcon() const
00237 {
00238 if( leader_client != NULL )
00239 return leader_client->miniIcon();
00240 else if( leader_wid != None )
00241 {
00242 QPixmap ic;
00243 Client::readIcons( leader_wid, NULL, &ic );
00244 return ic;
00245 }
00246 return QPixmap();
00247 }
00248
00249 void Group::addMember( Client* member_P )
00250 {
00251 TRANSIENCY_CHECK( member_P );
00252 _members.append( member_P );
00253
00254
00255 }
00256
00257 void Group::removeMember( Client* member_P )
00258 {
00259 TRANSIENCY_CHECK( member_P );
00260
00261
00262 Q_ASSERT( _members.contains( member_P ));
00263 _members.remove( member_P );
00264
00265
00266
00267
00268 if( refcount == 0 && _members.isEmpty())
00269 {
00270 workspace()->removeGroup( this, Allowed );
00271 delete this;
00272 }
00273 }
00274
00275 void Group::ref()
00276 {
00277 ++refcount;
00278 }
00279
00280 void Group::deref()
00281 {
00282 if( --refcount == 0 && _members.isEmpty())
00283 {
00284 workspace()->removeGroup( this, Allowed );
00285 delete this;
00286 }
00287 }
00288
00289 void Group::gotLeader( Client* leader_P )
00290 {
00291 assert( leader_P->window() == leader_wid );
00292 leader_client = leader_P;
00293 }
00294
00295 void Group::lostLeader()
00296 {
00297 assert( !_members.contains( leader_client ));
00298 leader_client = NULL;
00299 if( _members.isEmpty())
00300 {
00301 workspace()->removeGroup( this, Allowed );
00302 delete this;
00303 }
00304 }
00305
00306 void Group::getIcons()
00307 {
00308
00309 }
00310
00311
00312
00313
00314
00315 Group* Workspace::findGroup( Window leader ) const
00316 {
00317 assert( leader != None );
00318 for( GroupList::ConstIterator it = groups.begin();
00319 it != groups.end();
00320 ++it )
00321 if( (*it)->leader() == leader )
00322 return *it;
00323 return NULL;
00324 }
00325
00326
00327
00328 Group* Workspace::findClientLeaderGroup( const Client* c ) const
00329 {
00330 TRANSIENCY_CHECK( c );
00331 Group* ret = NULL;
00332 for( ClientList::ConstIterator it = clients.begin();
00333 it != clients.end();
00334 ++it )
00335 {
00336 if( *it == c )
00337 continue;
00338 if( (*it)->wmClientLeader() == c->wmClientLeader())
00339 {
00340 if( ret == NULL || ret == (*it)->group())
00341 ret = (*it)->group();
00342 else
00343 {
00344
00345
00346
00347
00348 ClientList old_group = (*it)->group()->members();
00349
00350 for( unsigned int pos = 0;
00351 pos < old_group.count();
00352 ++pos )
00353 {
00354 Client* tmp = old_group[ pos ];
00355 if( tmp != c )
00356 tmp->changeClientLeaderGroup( ret );
00357 }
00358 }
00359 }
00360 }
00361 return ret;
00362 }
00363
00364 void Workspace::updateMinimizedOfTransients( Client* c )
00365 {
00366
00367 if ( c->isMinimized() || c->isShade() )
00368 {
00369 for( ClientList::ConstIterator it = c->transients().begin();
00370 it != c->transients().end();
00371 ++it )
00372 {
00373 if( !(*it)->isMinimized()
00374 && !(*it)->isTopMenu() )
00375 {
00376 (*it)->minimize( true );
00377 updateMinimizedOfTransients( (*it) );
00378 }
00379 }
00380 }
00381 else
00382 {
00383 for( ClientList::ConstIterator it = c->transients().begin();
00384 it != c->transients().end();
00385 ++it )
00386 {
00387 if( (*it)->isMinimized()
00388 && !(*it)->isTopMenu())
00389 {
00390 (*it)->unminimize( true );
00391 updateMinimizedOfTransients( (*it) );
00392 }
00393 }
00394 }
00395 }
00396
00397
00401 void Workspace::updateOnAllDesktopsOfTransients( Client* c )
00402 {
00403 for( ClientList::ConstIterator it = c->transients().begin();
00404 it != c->transients().end();
00405 ++it)
00406 {
00407 if( (*it)->isOnAllDesktops() != c->isOnAllDesktops())
00408 (*it)->setOnAllDesktops( c->isOnAllDesktops());
00409 }
00410 }
00411
00412
00413 void Workspace::checkTransients( Window w )
00414 {
00415 TRANSIENCY_CHECK( NULL );
00416 for( ClientList::ConstIterator it = clients.begin();
00417 it != clients.end();
00418 ++it )
00419 (*it)->checkTransient( w );
00420 }
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 bool Client::resourceMatch( const Client* c1, const Client* c2 )
00431 {
00432
00433 if( qstrncmp( c1->resourceClass(), "xv", 2 ) == 0 && c1->resourceName() == "xv" )
00434 return qstrncmp( c2->resourceClass(), "xv", 2 ) == 0 && c2->resourceName() == "xv";
00435
00436 if( c1->resourceName() == "mozilla" )
00437 return c2->resourceName() == "mozilla";
00438 return c1->resourceClass() == c2->resourceClass();
00439 }
00440
00441 bool Client::belongToSameApplication( const Client* c1, const Client* c2, bool active_hack )
00442 {
00443 bool same_app = false;
00444
00445
00446 if( c1 == c2 )
00447 same_app = true;
00448 else if( c1->isTransient() && c2->hasTransient( c1, true ))
00449 same_app = true;
00450 else if( c2->isTransient() && c1->hasTransient( c2, true ))
00451 same_app = true;
00452 else if( c1->group() == c2->group())
00453 same_app = true;
00454 else if( c1->wmClientLeader() == c2->wmClientLeader()
00455 && c1->wmClientLeader() != c1->window()
00456 && c2->wmClientLeader() != c2->window())
00457 same_app = true;
00458
00459
00460 else if( c1->pid() != c2->pid()
00461 || c1->wmClientMachine( false ) != c2->wmClientMachine( false ))
00462 ;
00463 else if( c1->wmClientLeader() != c2->wmClientLeader()
00464 && c1->wmClientLeader() != c1->window()
00465 && c2->wmClientLeader() != c2->window())
00466 ;
00467 else if( !resourceMatch( c1, c2 ))
00468 ;
00469 else if( !sameAppWindowRoleMatch( c1, c2, active_hack ))
00470 ;
00471 else if( c1->pid() == 0 || c2->pid() == 0 )
00472 ;
00473
00474 else
00475 same_app = true;
00476
00477 return same_app;
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 bool Client::sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack )
00491 {
00492 if( c1->isTransient())
00493 {
00494 while( c1->transientFor() != NULL )
00495 c1 = c1->transientFor();
00496 if( c1->groupTransient())
00497 return c1->group() == c2->group();
00498 #if 0
00499
00500
00501
00502 || c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
00503 #endif
00504 }
00505 if( c2->isTransient())
00506 {
00507 while( c2->transientFor() != NULL )
00508 c2 = c2->transientFor();
00509 if( c2->groupTransient())
00510 return c1->group() == c2->group();
00511 #if 0
00512 || c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
00513 #endif
00514 }
00515 int pos1 = c1->windowRole().find( '#' );
00516 int pos2 = c2->windowRole().find( '#' );
00517 if(( pos1 >= 0 && pos2 >= 0 )
00518 ||
00519
00520
00521 c1->resourceName() == "mozilla" && c2->resourceName() == "mozilla" )
00522 {
00523 if( !active_hack )
00524 return c1 == c2;
00525 if( !c1->isActive() && !c2->isActive())
00526 return c1 == c2;
00527 else
00528 return true;
00529 }
00530 return true;
00531 }
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 void Client::readTransient()
00580 {
00581 TRANSIENCY_CHECK( this );
00582 Window new_transient_for_id;
00583 if( XGetTransientForHint( qt_xdisplay(), window(), &new_transient_for_id ))
00584 {
00585 original_transient_for_id = new_transient_for_id;
00586 new_transient_for_id = verifyTransientFor( new_transient_for_id, true );
00587 }
00588 else
00589 {
00590 original_transient_for_id = None;
00591 new_transient_for_id = verifyTransientFor( None, false );
00592 }
00593 setTransient( new_transient_for_id );
00594 }
00595
00596 void Client::setTransient( Window new_transient_for_id )
00597 {
00598 TRANSIENCY_CHECK( this );
00599 if( new_transient_for_id != transient_for_id )
00600 {
00601 removeFromMainClients();
00602 transient_for = NULL;
00603 transient_for_id = new_transient_for_id;
00604 if( transient_for_id != None && !groupTransient())
00605 {
00606 transient_for = workspace()->findClient( WindowMatchPredicate( transient_for_id ));
00607 assert( transient_for != NULL );
00608 transient_for->addTransient( this );
00609 }
00610 checkGroup( NULL, true );
00611 if( isTopMenu())
00612 workspace()->updateCurrentTopMenu();
00613 workspace()->updateClientLayer( this );
00614 }
00615 }
00616
00617 void Client::removeFromMainClients()
00618 {
00619 TRANSIENCY_CHECK( this );
00620 if( transientFor() != NULL )
00621 transientFor()->removeTransient( this );
00622 if( groupTransient())
00623 {
00624 for( ClientList::ConstIterator it = group()->members().begin();
00625 it != group()->members().end();
00626 ++it )
00627 (*it)->removeTransient( this );
00628 }
00629 }
00630
00631
00632
00633
00634
00635 void Client::cleanGrouping()
00636 {
00637 TRANSIENCY_CHECK( this );
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649 removeFromMainClients();
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 for( ClientList::ConstIterator it = transients_list.begin();
00661 it != transients_list.end();
00662 )
00663 {
00664 if( (*it)->transientFor() == this )
00665 {
00666 ClientList::ConstIterator it2 = it++;
00667 removeTransient( *it2 );
00668 }
00669 else
00670 ++it;
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 ClientList group_members = group()->members();
00688 group()->removeMember( this );
00689 in_group = NULL;
00690 for( ClientList::ConstIterator it = group_members.begin();
00691 it != group_members.end();
00692 ++it )
00693 (*it)->removeTransient( this );
00694
00695
00696
00697
00698
00699 }
00700
00701
00702
00703
00704
00705 void Client::checkGroupTransients()
00706 {
00707 TRANSIENCY_CHECK( this );
00708 for( ClientList::ConstIterator it1 = group()->members().begin();
00709 it1 != group()->members().end();
00710 ++it1 )
00711 {
00712 if( !(*it1)->groupTransient())
00713 continue;
00714 for( ClientList::ConstIterator it2 = group()->members().begin();
00715 it2 != group()->members().end();
00716 ++it2 )
00717 {
00718 if( *it1 == *it2 )
00719 continue;
00720 for( Client* cl = (*it2)->transientFor();
00721 cl != NULL;
00722 cl = cl->transientFor())
00723 {
00724 if( cl == *it1 )
00725 {
00726 (*it2)->transients_list.remove( *it1 );
00727 continue;
00728 }
00729 }
00730
00731
00732
00733
00734 if( (*it2)->groupTransient() && (*it1)->hasTransient( *it2, true ) && (*it2)->hasTransient( *it1, true ))
00735 (*it2)->transients_list.remove( *it1 );
00736
00737
00738
00739
00740
00741 for( ClientList::ConstIterator it3 = group()->members().begin();
00742 it3 != group()->members().end();
00743 ++it3 )
00744 {
00745 if( *it1 == *it2 || *it2 == *it3 || *it1 == *it3 )
00746 continue;
00747 if( (*it2)->hasTransient( *it1, false ) && (*it3)->hasTransient( *it1, false ))
00748 {
00749 if( (*it2)->hasTransient( *it3, true ))
00750 (*it3)->transients_list.remove( *it1 );
00751 if( (*it3)->hasTransient( *it2, true ))
00752 (*it2)->transients_list.remove( *it1 );
00753 }
00754 }
00755 }
00756 }
00757 }
00758
00762 Window Client::verifyTransientFor( Window new_transient_for, bool defined )
00763 {
00764 Window new_property_value = new_transient_for;
00765
00766
00767 if( isSplash() && new_transient_for == None )
00768 new_transient_for = workspace()->rootWin();
00769 if( new_transient_for == None )
00770 if( defined )
00771 new_property_value = new_transient_for = workspace()->rootWin();
00772 else
00773 return None;
00774 if( new_transient_for == window())
00775 {
00776 kdWarning( 1216 ) << "Client " << this << " has WM_TRANSIENT_FOR poiting to itself." << endl;
00777 new_property_value = new_transient_for = workspace()->rootWin();
00778 }
00779
00780
00781
00782 WId before_search = new_transient_for;
00783 while( new_transient_for != None
00784 && new_transient_for != workspace()->rootWin()
00785 && !workspace()->findClient( WindowMatchPredicate( new_transient_for )))
00786 {
00787 Window root_return, parent_return;
00788 Window* wins = NULL;
00789 unsigned int nwins;
00790 int r = XQueryTree(qt_xdisplay(), new_transient_for, &root_return, &parent_return, &wins, &nwins);
00791 if ( wins )
00792 XFree((void *) wins);
00793 if ( r == 0)
00794 break;
00795 new_transient_for = parent_return;
00796 }
00797 if( Client* new_transient_for_client = workspace()->findClient( WindowMatchPredicate( new_transient_for )))
00798 {
00799 if( new_transient_for != before_search )
00800 {
00801 kdDebug( 1212 ) << "Client " << this << " has WM_TRANSIENT_FOR poiting to non-toplevel window "
00802 << before_search << ", child of " << new_transient_for_client << ", adjusting." << endl;
00803 new_property_value = new_transient_for;
00804 }
00805 }
00806 else
00807 new_transient_for = before_search;
00808
00809
00810
00811 int count = 20;
00812 Window loop_pos = new_transient_for;
00813 while( loop_pos != None && loop_pos != workspace()->rootWin())
00814 {
00815 Client* pos = workspace()->findClient( WindowMatchPredicate( loop_pos ));
00816 if( pos == NULL )
00817 break;
00818 loop_pos = pos->transient_for_id;
00819 if( --count == 0 )
00820 {
00821 kdWarning( 1216 ) << "Client " << this << " caused WM_TRANSIENT_FOR loop." << endl;
00822 new_transient_for = workspace()->rootWin();
00823 }
00824 }
00825 if( new_transient_for != workspace()->rootWin()
00826 && workspace()->findClient( WindowMatchPredicate( new_transient_for )) == NULL )
00827 {
00828 new_transient_for = workspace()->rootWin();
00829 }
00830 if( new_property_value != original_transient_for_id )
00831 XSetTransientForHint( qt_xdisplay(), window(), new_property_value );
00832 return new_transient_for;
00833 }
00834
00835 void Client::addTransient( Client* cl )
00836 {
00837 TRANSIENCY_CHECK( this );
00838 assert( !transients_list.contains( cl ));
00839
00840 assert( cl != this );
00841 transients_list.append( cl );
00842 if( workspace()->mostRecentlyActivatedClient() == this && cl->isModal())
00843 check_active_modal = true;
00844
00845
00846
00847
00848
00849
00850 }
00851
00852 void Client::removeTransient( Client* cl )
00853 {
00854 TRANSIENCY_CHECK( this );
00855
00856
00857 transients_list.remove( cl );
00858
00859
00860 if( cl->transientFor() == this )
00861 {
00862 cl->transient_for_id = None;
00863 cl->transient_for = NULL;
00864
00865 cl->setTransient( None );
00866 }
00867 }
00868
00869
00870 void Client::checkTransient( Window w )
00871 {
00872 TRANSIENCY_CHECK( this );
00873 if( original_transient_for_id != w )
00874 return;
00875 w = verifyTransientFor( w, true );
00876 setTransient( w );
00877 }
00878
00879
00880
00881 bool Client::hasTransient( const Client* cl, bool indirect ) const
00882 {
00883
00884 ConstClientList set;
00885 return hasTransientInternal( cl, indirect, set );
00886 }
00887
00888 bool Client::hasTransientInternal( const Client* cl, bool indirect, ConstClientList& set ) const
00889 {
00890 if( cl->transientFor() != NULL )
00891 {
00892 if( cl->transientFor() == this )
00893 return true;
00894 if( !indirect )
00895 return false;
00896 if( set.contains( cl ))
00897 return false;
00898 set.append( cl );
00899 return hasTransientInternal( cl->transientFor(), indirect, set );
00900 }
00901 if( !cl->isTransient())
00902 return false;
00903 if( group() != cl->group())
00904 return false;
00905
00906 if( transients().contains( const_cast< Client* >( cl )))
00907 return true;
00908 if( !indirect )
00909 return false;
00910 if( set.contains( this ))
00911 return false;
00912 set.append( this );
00913 for( ClientList::ConstIterator it = transients().begin();
00914 it != transients().end();
00915 ++it )
00916 if( (*it)->hasTransientInternal( cl, indirect, set ))
00917 return true;
00918 return false;
00919 }
00920
00921 ClientList Client::mainClients() const
00922 {
00923 if( !isTransient())
00924 return ClientList();
00925 if( transientFor() != NULL )
00926 return ClientList() << const_cast< Client* >( transientFor());
00927 ClientList result;
00928 for( ClientList::ConstIterator it = group()->members().begin();
00929 it != group()->members().end();
00930 ++it )
00931 if((*it)->hasTransient( this, false ))
00932 result.append( *it );
00933 return result;
00934 }
00935
00936 Client* Client::findModal()
00937 {
00938 for( ClientList::ConstIterator it = transients().begin();
00939 it != transients().end();
00940 ++it )
00941 if( Client* ret = (*it)->findModal())
00942 return ret;
00943 if( isModal())
00944 return this;
00945 return NULL;
00946 }
00947
00948
00949
00950
00951 void Client::checkGroup( Group* set_group, bool force )
00952 {
00953 TRANSIENCY_CHECK( this );
00954 Group* old_group = in_group;
00955 if( old_group != NULL )
00956 old_group->ref();
00957 if( set_group != NULL )
00958 {
00959 if( set_group != in_group )
00960 {
00961 if( in_group != NULL )
00962 in_group->removeMember( this );
00963 in_group = set_group;
00964 in_group->addMember( this );
00965 }
00966 }
00967 else if( window_group != None )
00968 {
00969 Group* new_group = workspace()->findGroup( window_group );
00970 if( transientFor() != NULL && transientFor()->group() != new_group )
00971 {
00972
00973 new_group = transientFor()->group();
00974 }
00975 if( new_group == NULL )
00976 new_group = new Group( window_group, workspace());
00977 if( new_group != in_group )
00978 {
00979 if( in_group != NULL )
00980 in_group->removeMember( this );
00981 in_group = new_group;
00982 in_group->addMember( this );
00983 }
00984 }
00985 else
00986 {
00987 if( transientFor() != NULL )
00988 {
00989
00990 Group* new_group = transientFor()->group();
00991 if( new_group != in_group )
00992 {
00993 if( in_group != NULL )
00994 in_group->removeMember( this );
00995 in_group = transientFor()->group();
00996 in_group->addMember( this );
00997 }
00998 }
00999 else if( groupTransient())
01000 {
01001
01002 Group* new_group = workspace()->findClientLeaderGroup( this );
01003 if( new_group == NULL )
01004 new_group = new Group( None, workspace());
01005 if( new_group != in_group )
01006 {
01007 if( in_group != NULL )
01008 in_group->removeMember( this );
01009 in_group = new_group;
01010 in_group->addMember( this );
01011 }
01012 }
01013 else
01014 {
01015
01016
01017 Group* new_group = workspace()->findClientLeaderGroup( this );
01018 if( in_group != NULL && in_group != new_group )
01019 {
01020 in_group->removeMember( this );
01021 in_group = NULL;
01022 }
01023 if( new_group == NULL )
01024 new_group = new Group( None, workspace() );
01025 if( in_group != new_group )
01026 {
01027 in_group = new_group;
01028 in_group->addMember( this );
01029 }
01030 }
01031 }
01032 if( in_group != old_group || force )
01033 {
01034 for( ClientList::Iterator it = transients_list.begin();
01035 it != transients_list.end();
01036 )
01037 {
01038 if( (*it)->groupTransient() && (*it)->group() != group())
01039 it = transients_list.remove( it );
01040 else
01041 ++it;
01042 }
01043 if( groupTransient())
01044 {
01045
01046 if( old_group != NULL )
01047 {
01048 for( ClientList::ConstIterator it = old_group->members().begin();
01049 it != old_group->members().end();
01050 ++it )
01051 (*it)->removeTransient( this );
01052 }
01053
01054 for( ClientList::ConstIterator it = group()->members().begin();
01055 it != group()->members().end();
01056 ++it )
01057 {
01058 if( *it == this )
01059 break;
01060 (*it)->addTransient( this );
01061 }
01062 }
01063
01064
01065 for( ClientList::ConstIterator it = group()->members().begin();
01066 it != group()->members().end();
01067 ++it )
01068 {
01069 if( !(*it)->isSplash())
01070 continue;
01071 if( !(*it)->groupTransient())
01072 continue;
01073 if( *it == this || hasTransient( *it, true ))
01074 continue;
01075 addTransient( *it );
01076 }
01077 }
01078 if( old_group != NULL )
01079 old_group->deref();
01080 checkGroupTransients();
01081 checkActiveModal();
01082 workspace()->updateClientLayer( this );
01083 }
01084
01085
01086 void Client::changeClientLeaderGroup( Group* gr )
01087 {
01088
01089 if( transientFor() != NULL )
01090 return;
01091
01092 if( window_group )
01093 return;
01094 checkGroup( gr );
01095 }
01096
01097 bool Client::check_active_modal = false;
01098
01099 void Client::checkActiveModal()
01100 {
01101
01102
01103
01104 Client* check_modal = workspace()->mostRecentlyActivatedClient();
01105 if( check_modal != NULL && check_modal->check_active_modal )
01106 {
01107 Client* new_modal = check_modal->findModal();
01108 if( new_modal != NULL && new_modal != check_modal )
01109 {
01110 if( !new_modal->isManaged())
01111 return;
01112 workspace()->activateClient( new_modal );
01113 }
01114 check_modal->check_active_modal = false;
01115 }
01116 }
01117
01118 }