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