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