20 #include "workspace.h"
24 #include <tdestartupinfo.h>
33 namespace KWinInternal
44 #undef ENABLE_TRANSIENCY_CHECK
47 #ifdef ENABLE_TRANSIENCY_CHECK
48 static bool transiencyCheckNonExistent =
false;
50 bool performTransiencyCheck()
53 ClientList clients = Workspace::self()->clients;
54 for( ClientList::ConstIterator it1 = clients.begin();
58 if( (*it1)->deleting )
60 if( (*it1)->in_group == NULL )
62 kdDebug() <<
"TC: " << *it1 <<
" in not in a group" << endl;
65 else if( !(*it1)->in_group->members().contains( *it1 ))
67 kdDebug() <<
"TC: " << *it1 <<
" has a group " << (*it1)->in_group <<
" but group does not contain it" << endl;
70 if( !(*it1)->isTransient())
72 if( !(*it1)->mainClients().isEmpty())
74 kdDebug() <<
"TC: " << *it1 <<
" is not transient, has main clients:" << (*it1)->mainClients() << endl;
80 ClientList mains = (*it1)->mainClients();
81 for( ClientList::ConstIterator it2 = mains.begin();
85 if( transiencyCheckNonExistent
86 && !Workspace::self()->clients.contains( *it2 )
87 && !Workspace::self()->desktops.contains( *it2 ))
89 kdDebug() <<
"TC:" << *it1 <<
" has non-existent main client " << endl;
90 kdDebug() <<
"TC2:" << *it2 << endl;
94 if( !(*it2)->transients_list.contains( *it1 ))
96 kdDebug() <<
"TC:" << *it1 <<
" has main client " << *it2 <<
" but main client does not have it as a transient" << endl;
101 ClientList trans = (*it1)->transients_list;
102 for( ClientList::ConstIterator it2 = trans.begin();
106 if( transiencyCheckNonExistent
107 && !Workspace::self()->clients.contains( *it2 )
108 && !Workspace::self()->desktops.contains( *it2 ))
110 kdDebug() <<
"TC:" << *it1 <<
" has non-existent transient " << endl;
111 kdDebug() <<
"TC2:" << *it2 << endl;
115 if( !(*it2)->mainClients().contains( *it1 ))
117 kdDebug() <<
"TC:" << *it1 <<
" has transient " << *it2 <<
" but transient does not have it as a main client" << endl;
122 GroupList groups = Workspace::self()->groups;
123 for( GroupList::ConstIterator it1 = groups.begin();
127 ClientList members = (*it1)->members();
128 for( ClientList::ConstIterator it2 = members.begin();
129 it2 != members.end();
132 if( (*it2)->in_group != *it1 )
134 kdDebug() <<
"TC: Group " << *it1 <<
" contains client " << *it2 <<
" but client is not in that group" << endl;
142 static TQString transiencyCheckStartBt;
143 static const Client* transiencyCheckClient;
144 static int transiencyCheck = 0;
146 static void startTransiencyCheck(
const TQString& bt,
const Client* c,
bool ne )
148 if( ++transiencyCheck == 1 )
150 transiencyCheckStartBt = bt;
151 transiencyCheckClient = c;
154 transiencyCheckNonExistent =
true;
156 static void checkTransiency()
158 if( --transiencyCheck == 0 )
160 if( !performTransiencyCheck())
162 kdDebug() <<
"BT:" << transiencyCheckStartBt << endl;
163 kdDebug() <<
"CLIENT:" << transiencyCheckClient << endl;
166 transiencyCheckNonExistent =
false;
169 class TransiencyChecker
172 TransiencyChecker(
const TQString& bt,
const Client*c ) { startTransiencyCheck( bt, c,
false ); }
173 ~TransiencyChecker() { checkTransiency(); }
176 void checkNonExistentClients()
178 startTransiencyCheck( kdBacktrace(), NULL,
true );
182 #define TRANSIENCY_CHECK( c ) TransiencyChecker transiency_checker( kdBacktrace(), c )
186 #define TRANSIENCY_CHECK( c )
188 void checkNonExistentClients()
198 Group::Group( Window leader_P, Workspace* workspace_P )
199 : leader_client( NULL ),
200 leader_wid( leader_P ),
201 _workspace( workspace_P ),
206 if( leader_P != None )
208 leader_client = workspace_P->findClient( WindowMatchPredicate( leader_P ));
209 unsigned long properties[ 2 ] = { 0, NET::WM2StartupId };
210 leader_info =
new NETWinInfo( tqt_xdisplay(), leader_P, workspace()->rootWin(),
213 workspace()->addGroup(
this, Allowed );
221 TQPixmap Group::icon()
const
223 if( leader_client != NULL )
224 return leader_client->icon();
225 else if( leader_wid != None )
228 Client::readIcons( leader_wid, &ic, NULL );
234 TQPixmap Group::miniIcon()
const
236 if( leader_client != NULL )
237 return leader_client->miniIcon();
238 else if( leader_wid != None )
241 Client::readIcons( leader_wid, NULL, &ic );
247 void Group::addMember( Client* member_P )
249 TRANSIENCY_CHECK( member_P );
250 _members.append( member_P );
255 void Group::removeMember( Client* member_P )
257 TRANSIENCY_CHECK( member_P );
260 Q_ASSERT( _members.contains( member_P ));
261 _members.remove( member_P );
266 if( refcount == 0 && _members.isEmpty())
268 workspace()->removeGroup(
this, Allowed );
280 if( --refcount == 0 && _members.isEmpty())
282 workspace()->removeGroup(
this, Allowed );
287 void Group::gotLeader( Client* leader_P )
289 assert( leader_P->window() == leader_wid );
290 leader_client = leader_P;
293 void Group::lostLeader()
295 assert( !_members.contains( leader_client ));
296 leader_client = NULL;
297 if( _members.isEmpty())
299 workspace()->removeGroup(
this, Allowed );
304 void Group::getIcons()
313 Group* Workspace::findGroup( Window leader )
const
315 assert( leader != None );
316 for( GroupList::ConstIterator it = groups.begin();
319 if( (*it)->leader() == leader )
326 Group* Workspace::findClientLeaderGroup(
const Client* c )
const
328 TRANSIENCY_CHECK( c );
330 for( ClientList::ConstIterator it = clients.begin();
336 if( (*it)->wmClientLeader() == c->wmClientLeader())
338 if( ret == NULL || ret == (*it)->group())
339 ret = (*it)->group();
346 ClientList old_group = (*it)->group()->members();
348 for(
unsigned int pos = 0;
349 pos < old_group.count();
352 Client* tmp = old_group[ pos ];
354 tmp->changeClientLeaderGroup( ret );
362 void Workspace::updateMinimizedOfTransients( Client* c )
365 if ( c->isMinimized() || c->isShade() )
367 for( ClientList::ConstIterator it = c->transients().begin();
368 it != c->transients().end();
371 if( !(*it)->isMinimized()
372 && !(*it)->isTopMenu() )
374 (*it)->minimize(
true );
375 updateMinimizedOfTransients( (*it) );
381 for( ClientList::ConstIterator it = c->transients().begin();
382 it != c->transients().end();
385 if( (*it)->isMinimized()
386 && !(*it)->isTopMenu())
388 (*it)->unminimize(
true );
389 updateMinimizedOfTransients( (*it) );
399 void Workspace::updateOnAllDesktopsOfTransients( Client* c )
401 for( ClientList::ConstIterator it = c->transients().begin();
402 it != c->transients().end();
405 if( (*it)->isOnAllDesktops() != c->isOnAllDesktops())
406 (*it)->setOnAllDesktops( c->isOnAllDesktops());
411 void Workspace::checkTransients( Window w )
413 TRANSIENCY_CHECK( NULL );
414 for( ClientList::ConstIterator it = clients.begin();
417 (*it)->checkTransient( w );
428 bool Client::resourceMatch(
const Client* c1,
const Client* c2 )
431 if( tqstrncmp( c1->resourceClass(),
"xv", 2 ) == 0 && c1->resourceName() ==
"xv" )
432 return tqstrncmp( c2->resourceClass(),
"xv", 2 ) == 0 && c2->resourceName() ==
"xv";
434 if( c1->resourceName() ==
"mozilla" )
435 return c2->resourceName() ==
"mozilla";
436 return c1->resourceClass() == c2->resourceClass();
439 bool Client::belongToSameApplication(
const Client* c1,
const Client* c2,
bool active_hack )
441 bool same_app =
false;
446 else if( c1->isTransient() && c2->hasTransient( c1,
true ))
448 else if( c2->isTransient() && c1->hasTransient( c2,
true ))
450 else if( c1->group() == c2->group())
452 else if( c1->wmClientLeader() == c2->wmClientLeader()
453 && c1->wmClientLeader() != c1->window()
454 && c2->wmClientLeader() != c2->window())
458 else if( c1->pid() != c2->pid()
459 || c1->wmClientMachine(
false ) != c2->wmClientMachine(
false ))
461 else if( c1->wmClientLeader() != c2->wmClientLeader()
462 && c1->wmClientLeader() != c1->window()
463 && c2->wmClientLeader() != c2->window())
465 else if( !resourceMatch( c1, c2 ))
467 else if( !sameAppWindowRoleMatch( c1, c2, active_hack ))
469 else if( c1->pid() == 0 || c2->pid() == 0 )
488 bool Client::sameAppWindowRoleMatch(
const Client* c1,
const Client* c2,
bool active_hack )
490 if( c1->isTransient())
492 while( c1->transientFor() != NULL )
493 c1 = c1->transientFor();
494 if( c1->groupTransient())
495 return c1->group() == c2->group();
500 || c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
503 if( c2->isTransient())
505 while( c2->transientFor() != NULL )
506 c2 = c2->transientFor();
507 if( c2->groupTransient())
508 return c1->group() == c2->group();
510 || c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
513 int pos1 = c1->windowRole().find(
'#' );
514 int pos2 = c2->windowRole().find(
'#' );
515 if(( pos1 >= 0 && pos2 >= 0 )
519 ((c1->resourceName() ==
"mozilla") && (c2->resourceName() ==
"mozilla")) )
523 if( !c1->isActive() && !c2->isActive())
577 void Client::readTransient()
579 TRANSIENCY_CHECK(
this );
580 Window new_transient_for_id;
581 if( XGetTransientForHint( tqt_xdisplay(), window(), &new_transient_for_id ))
583 original_transient_for_id = new_transient_for_id;
584 new_transient_for_id = verifyTransientFor( new_transient_for_id,
true );
588 original_transient_for_id = None;
589 new_transient_for_id = verifyTransientFor( None,
false );
591 setTransient( new_transient_for_id );
594 void Client::setTransient( Window new_transient_for_id )
596 TRANSIENCY_CHECK(
this );
597 if( new_transient_for_id != transient_for_id )
599 removeFromMainClients();
600 transient_for = NULL;
601 transient_for_id = new_transient_for_id;
602 if( transient_for_id != None && !groupTransient())
604 transient_for = workspace()->findClient( WindowMatchPredicate( transient_for_id ));
605 assert( transient_for != NULL );
606 transient_for->addTransient(
this );
608 checkGroup( NULL,
true );
610 workspace()->updateCurrentTopMenu();
611 workspace()->updateClientLayer(
this );
615 void Client::removeFromMainClients()
617 TRANSIENCY_CHECK(
this );
618 if( transientFor() != NULL )
619 transientFor()->removeTransient(
this );
620 if( groupTransient())
622 for( ClientList::ConstIterator it = group()->members().begin();
623 it != group()->members().end();
625 (*it)->removeTransient(
this );
633 void Client::cleanGrouping()
635 TRANSIENCY_CHECK(
this );
647 removeFromMainClients();
658 for( ClientList::ConstIterator it = transients_list.begin();
659 it != transients_list.end();
662 if( (*it)->transientFor() ==
this )
664 ClientList::ConstIterator it2 = it++;
665 removeTransient( *it2 );
685 ClientList group_members = group()->members();
686 group()->removeMember(
this );
688 for( ClientList::ConstIterator it = group_members.begin();
689 it != group_members.end();
691 (*it)->removeTransient(
this );
703 void Client::checkGroupTransients()
705 TRANSIENCY_CHECK(
this );
706 for( ClientList::ConstIterator it1 = group()->members().begin();
707 it1 != group()->members().end();
710 if( !(*it1)->groupTransient())
712 for( ClientList::ConstIterator it2 = group()->members().begin();
713 it2 != group()->members().end();
718 for( Client* cl = (*it2)->transientFor();
720 cl = cl->transientFor())
724 (*it2)->transients_list.remove( *it1 );
732 if( (*it2)->groupTransient() && (*it1)->hasTransient( *it2,
true ) && (*it2)->hasTransient( *it1,
true ))
733 (*it2)->transients_list.remove( *it1 );
739 for( ClientList::ConstIterator it3 = group()->members().begin();
740 it3 != group()->members().end();
743 if( *it1 == *it2 || *it2 == *it3 || *it1 == *it3 )
745 if( (*it2)->hasTransient( *it1,
false ) && (*it3)->hasTransient( *it1,
false ))
747 if( (*it2)->hasTransient( *it3,
true ))
748 (*it2)->transients_list.remove( *it1 );
749 if( (*it3)->hasTransient( *it2,
true ))
750 (*it3)->transients_list.remove( *it1 );
760 Window Client::verifyTransientFor( Window new_transient_for,
bool defined )
762 Window new_property_value = new_transient_for;
765 if( isSplash() && new_transient_for == None )
766 new_transient_for = workspace()->rootWin();
767 if( new_transient_for == None )
769 new_property_value = new_transient_for = workspace()->rootWin();
772 if( new_transient_for == window())
774 kdWarning( 1216 ) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to itself." << endl;
775 new_property_value = new_transient_for = workspace()->rootWin();
780 WId before_search = new_transient_for;
781 while( new_transient_for != None
782 && new_transient_for != workspace()->rootWin()
783 && !workspace()->findClient( WindowMatchPredicate( new_transient_for )))
785 Window root_return, parent_return;
788 int r = XQueryTree(tqt_xdisplay(), new_transient_for, &root_return, &parent_return, &wins, &nwins);
790 XFree((
void *) wins);
793 new_transient_for = parent_return;
795 if( Client* new_transient_for_client = workspace()->findClient( WindowMatchPredicate( new_transient_for )))
797 if( new_transient_for != before_search )
799 kdDebug( 1212 ) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to non-toplevel window "
800 << before_search <<
", child of " << new_transient_for_client <<
", adjusting." << endl;
801 new_property_value = new_transient_for;
805 new_transient_for = before_search;
810 Window loop_pos = new_transient_for;
811 while( loop_pos != None && loop_pos != workspace()->rootWin())
813 Client* pos = workspace()->findClient( WindowMatchPredicate( loop_pos ));
816 loop_pos = pos->transient_for_id;
817 if( --count == 0 || pos ==
this )
819 kdWarning( 1216 ) <<
"Client " <<
this <<
" caused WM_TRANSIENT_FOR loop." << endl;
820 new_transient_for = workspace()->rootWin();
823 if( new_transient_for != workspace()->rootWin()
824 && workspace()->findClient( WindowMatchPredicate( new_transient_for )) == NULL )
826 new_transient_for = workspace()->rootWin();
828 if( new_property_value != original_transient_for_id )
829 XSetTransientForHint( tqt_xdisplay(), window(), new_property_value );
830 return new_transient_for;
833 void Client::addTransient( Client* cl )
835 TRANSIENCY_CHECK(
this );
836 assert( !transients_list.contains( cl ));
838 assert( cl !=
this );
839 transients_list.append( cl );
840 if( workspace()->mostRecentlyActivatedClient() ==
this && cl->isModal())
841 check_active_modal =
true;
850 void Client::removeTransient( Client* cl )
852 TRANSIENCY_CHECK(
this );
855 transients_list.remove( cl );
858 if( cl->transientFor() ==
this )
860 cl->transient_for_id = None;
861 cl->transient_for = NULL;
863 cl->setTransient( None );
868 void Client::checkTransient( Window w )
870 TRANSIENCY_CHECK(
this );
871 if( original_transient_for_id != w )
873 w = verifyTransientFor( w,
true );
879 bool Client::hasTransient(
const Client* cl,
bool indirect )
const
883 return hasTransientInternal( cl, indirect, set );
886 bool Client::hasTransientInternal(
const Client* cl,
bool indirect, ConstClientList& set )
const
888 if( cl->transientFor() != NULL )
890 if( cl->transientFor() ==
this )
894 if( set.contains( cl ))
897 return hasTransientInternal( cl->transientFor(), indirect, set );
899 if( !cl->isTransient())
901 if( group() != cl->group())
904 if( transients().contains(
const_cast< Client*
>( cl )))
908 if( set.contains(
this ))
911 for( ClientList::ConstIterator it = transients().begin();
912 it != transients().end();
914 if( (*it)->hasTransientInternal( cl, indirect, set ))
919 ClientList Client::mainClients()
const
923 if( transientFor() != NULL )
924 return ClientList() <<
const_cast< Client*
>( transientFor());
926 for( ClientList::ConstIterator it = group()->members().begin();
927 it != group()->members().end();
929 if((*it)->hasTransient(
this,
false ))
930 result.append( *it );
934 Client* Client::findModal()
936 for( ClientList::ConstIterator it = transients().begin();
937 it != transients().end();
939 if( Client* ret = (*it)->findModal())
949 void Client::checkGroup( Group* set_group,
bool force )
951 TRANSIENCY_CHECK(
this );
952 Group* old_group = in_group;
953 if( old_group != NULL )
955 if( set_group != NULL )
957 if( set_group != in_group )
959 if( in_group != NULL )
960 in_group->removeMember(
this );
961 in_group = set_group;
962 in_group->addMember(
this );
965 else if( window_group != None )
967 Group* new_group = workspace()->findGroup( window_group );
968 if( transientFor() != NULL && transientFor()->group() != new_group )
971 new_group = transientFor()->group();
973 if( new_group == NULL )
974 new_group =
new Group( window_group, workspace());
975 if( new_group != in_group )
977 if( in_group != NULL )
978 in_group->removeMember(
this );
979 in_group = new_group;
980 in_group->addMember(
this );
985 if( transientFor() != NULL )
988 Group* new_group = transientFor()->group();
989 if( new_group != in_group )
991 if( in_group != NULL )
992 in_group->removeMember(
this );
993 in_group = transientFor()->group();
994 in_group->addMember(
this );
997 else if( groupTransient())
1000 Group* new_group = workspace()->findClientLeaderGroup(
this );
1001 if( new_group == NULL )
1002 new_group =
new Group( None, workspace());
1003 if( new_group != in_group )
1005 if( in_group != NULL )
1006 in_group->removeMember(
this );
1007 in_group = new_group;
1008 in_group->addMember(
this );
1015 Group* new_group = workspace()->findClientLeaderGroup(
this );
1016 if( in_group != NULL && in_group != new_group )
1018 in_group->removeMember(
this );
1021 if( new_group == NULL )
1022 new_group =
new Group( None, workspace() );
1023 if( in_group != new_group )
1025 in_group = new_group;
1026 in_group->addMember(
this );
1030 if( in_group != old_group || force )
1032 for( ClientList::Iterator it = transients_list.begin();
1033 it != transients_list.end();
1036 if( (*it)->groupTransient() && (*it)->group() != group())
1037 it = transients_list.remove( it );
1041 if( groupTransient())
1044 if( old_group != NULL )
1046 for( ClientList::ConstIterator it = old_group->members().begin();
1047 it != old_group->members().end();
1049 (*it)->removeTransient(
this );
1052 for( ClientList::ConstIterator it = group()->members().begin();
1053 it != group()->members().end();
1058 (*it)->addTransient(
this );
1063 for( ClientList::ConstIterator it = group()->members().begin();
1064 it != group()->members().end();
1067 if( !(*it)->isSplash())
1069 if( !(*it)->groupTransient())
1071 if( *it ==
this || hasTransient( *it,
true ))
1073 addTransient( *it );
1076 if( old_group != NULL )
1078 checkGroupTransients();
1080 workspace()->updateClientLayer(
this );
1084 void Client::changeClientLeaderGroup( Group* gr )
1087 if( transientFor() != NULL )
1095 bool Client::check_active_modal =
false;
1097 void Client::checkActiveModal()
1102 Client* check_modal = workspace()->mostRecentlyActivatedClient();
1103 if( check_modal != NULL && check_modal->check_active_modal )
1105 Client* new_modal = check_modal->findModal();
1106 if( new_modal != NULL && new_modal != check_modal )
1108 if( !new_modal->isManaged())
1110 workspace()->activateClient( new_modal );
1112 check_modal->check_active_modal =
false;