22 #include "workspace.h"
26 #include <tdestartupinfo.h>
35 namespace KWinInternal
46 #undef ENABLE_TRANSIENCY_CHECK
49 #ifdef ENABLE_TRANSIENCY_CHECK
50 static bool transiencyCheckNonExistent =
false;
52 bool performTransiencyCheck()
55 ClientList clients = Workspace::self()->clients;
56 for( ClientList::ConstIterator it1 = clients.begin();
60 if( (*it1)->deleting )
62 if( (*it1)->in_group == NULL )
64 kdDebug() <<
"TC: " << *it1 <<
" in not in a group" << endl;
67 else if( !(*it1)->in_group->members().contains( *it1 ))
69 kdDebug() <<
"TC: " << *it1 <<
" has a group " << (*it1)->in_group <<
" but group does not contain it" << endl;
72 if( !(*it1)->isTransient())
74 if( !(*it1)->mainClients().isEmpty())
76 kdDebug() <<
"TC: " << *it1 <<
" is not transient, has main clients:" << (*it1)->mainClients() << endl;
82 ClientList mains = (*it1)->mainClients();
83 for( ClientList::ConstIterator it2 = mains.begin();
87 if( transiencyCheckNonExistent
88 && !Workspace::self()->clients.contains( *it2 )
89 && !Workspace::self()->desktops.contains( *it2 ))
91 kdDebug() <<
"TC:" << *it1 <<
" has non-existent main client " << endl;
92 kdDebug() <<
"TC2:" << *it2 << endl;
96 if( !(*it2)->transients_list.contains( *it1 ))
98 kdDebug() <<
"TC:" << *it1 <<
" has main client " << *it2 <<
" but main client does not have it as a transient" << endl;
103 ClientList trans = (*it1)->transients_list;
104 for( ClientList::ConstIterator it2 = trans.begin();
108 if( transiencyCheckNonExistent
109 && !Workspace::self()->clients.contains( *it2 )
110 && !Workspace::self()->desktops.contains( *it2 ))
112 kdDebug() <<
"TC:" << *it1 <<
" has non-existent transient " << endl;
113 kdDebug() <<
"TC2:" << *it2 << endl;
117 if( !(*it2)->mainClients().contains( *it1 ))
119 kdDebug() <<
"TC:" << *it1 <<
" has transient " << *it2 <<
" but transient does not have it as a main client" << endl;
124 GroupList groups = Workspace::self()->groups;
125 for( GroupList::ConstIterator it1 = groups.begin();
129 ClientList members = (*it1)->members();
130 for( ClientList::ConstIterator it2 = members.begin();
131 it2 != members.end();
134 if( (*it2)->in_group != *it1 )
136 kdDebug() <<
"TC: Group " << *it1 <<
" contains client " << *it2 <<
" but client is not in that group" << endl;
144 static TQString transiencyCheckStartBt;
145 static const Client* transiencyCheckClient;
146 static int transiencyCheck = 0;
148 static void startTransiencyCheck(
const TQString& bt,
const Client* c,
bool ne )
150 if( ++transiencyCheck == 1 )
152 transiencyCheckStartBt = bt;
153 transiencyCheckClient = c;
156 transiencyCheckNonExistent =
true;
158 static void checkTransiency()
160 if( --transiencyCheck == 0 )
162 if( !performTransiencyCheck())
164 kdDebug() <<
"BT:" << transiencyCheckStartBt << endl;
165 kdDebug() <<
"CLIENT:" << transiencyCheckClient << endl;
168 transiencyCheckNonExistent =
false;
171 class TransiencyChecker
174 TransiencyChecker(
const TQString& bt,
const Client*c ) { startTransiencyCheck( bt, c,
false ); }
175 ~TransiencyChecker() { checkTransiency(); }
178 void checkNonExistentClients()
180 startTransiencyCheck( kdBacktrace(), NULL,
true );
184 #define TRANSIENCY_CHECK( c ) TransiencyChecker transiency_checker( kdBacktrace(), c )
188 #define TRANSIENCY_CHECK( c )
190 void checkNonExistentClients()
200 Group::Group( Window leader_P, Workspace* workspace_P )
201 : leader_client( NULL ),
202 leader_wid( leader_P ),
203 _workspace( workspace_P ),
208 if( leader_P != None )
210 leader_client = workspace_P->findClient( WindowMatchPredicate( leader_P ));
211 unsigned long properties[ 2 ] = { 0, NET::WM2StartupId };
212 leader_info =
new NETWinInfo( tqt_xdisplay(), leader_P, workspace()->rootWin(),
215 workspace()->addGroup(
this, Allowed );
223 TQPixmap Group::icon()
const
225 if( leader_client != NULL )
226 return leader_client->icon();
227 else if( leader_wid != None )
230 Client::readIcons( leader_wid, &ic, NULL );
236 TQPixmap Group::miniIcon()
const
238 if( leader_client != NULL )
239 return leader_client->miniIcon();
240 else if( leader_wid != None )
243 Client::readIcons( leader_wid, NULL, &ic );
249 void Group::addMember( Client* member_P )
251 TRANSIENCY_CHECK( member_P );
252 _members.append( member_P );
257 void Group::removeMember( Client* member_P )
259 TRANSIENCY_CHECK( member_P );
262 Q_ASSERT( _members.contains( member_P ));
263 _members.remove( member_P );
268 if( refcount == 0 && _members.isEmpty())
270 workspace()->removeGroup(
this, Allowed );
282 if( --refcount == 0 && _members.isEmpty())
284 workspace()->removeGroup(
this, Allowed );
289 void Group::gotLeader( Client* leader_P )
291 assert( leader_P->window() == leader_wid );
292 leader_client = leader_P;
295 void Group::lostLeader()
297 assert( !_members.contains( leader_client ));
298 leader_client = NULL;
299 if( _members.isEmpty())
301 workspace()->removeGroup(
this, Allowed );
306 void Group::getIcons()
315 Group* Workspace::findGroup( Window leader )
const
317 assert( leader != None );
318 for( GroupList::ConstIterator it = groups.begin();
321 if( (*it)->leader() == leader )
328 Group* Workspace::findClientLeaderGroup(
const Client* c )
const
330 TRANSIENCY_CHECK( c );
332 for( ClientList::ConstIterator it = clients.begin();
338 if( (*it)->wmClientLeader() == c->wmClientLeader())
340 if( ret == NULL || ret == (*it)->group())
341 ret = (*it)->group();
348 ClientList old_group = (*it)->group()->members();
350 for(
unsigned int pos = 0;
351 pos < old_group.count();
354 Client* tmp = old_group[ pos ];
356 tmp->changeClientLeaderGroup( ret );
364 void Workspace::updateMinimizedOfTransients( Client* c )
367 if ( c->isMinimized() || c->isShade() )
369 for( ClientList::ConstIterator it = c->transients().begin();
370 it != c->transients().end();
373 if( !(*it)->isMinimized()
374 && !(*it)->isTopMenu() )
376 (*it)->minimize(
true );
377 updateMinimizedOfTransients( (*it) );
383 for( ClientList::ConstIterator it = c->transients().begin();
384 it != c->transients().end();
387 if( (*it)->isMinimized()
388 && !(*it)->isTopMenu())
390 (*it)->unminimize(
true );
391 updateMinimizedOfTransients( (*it) );
401 void Workspace::updateOnAllDesktopsOfTransients( Client* c )
403 for( ClientList::ConstIterator it = c->transients().begin();
404 it != c->transients().end();
407 if( (*it)->isOnAllDesktops() != c->isOnAllDesktops())
408 (*it)->setOnAllDesktops( c->isOnAllDesktops());
413 void Workspace::checkTransients( Window w )
415 TRANSIENCY_CHECK( NULL );
416 for( ClientList::ConstIterator it = clients.begin();
419 (*it)->checkTransient( w );
430 bool Client::resourceMatch(
const Client* c1,
const Client* c2 )
433 if( tqstrncmp( c1->resourceClass(),
"xv", 2 ) == 0 && c1->resourceName() ==
"xv" )
434 return tqstrncmp( c2->resourceClass(),
"xv", 2 ) == 0 && c2->resourceName() ==
"xv";
436 if( c1->resourceName() ==
"mozilla" )
437 return c2->resourceName() ==
"mozilla";
438 return c1->resourceClass() == c2->resourceClass();
441 bool Client::belongToSameApplication(
const Client* c1,
const Client* c2,
bool active_hack )
443 bool same_app =
false;
448 else if( c1->isTransient() && c2->hasTransient( c1,
true ))
450 else if( c2->isTransient() && c1->hasTransient( c2,
true ))
452 else if( c1->group() == c2->group())
454 else if( c1->wmClientLeader() == c2->wmClientLeader()
455 && c1->wmClientLeader() != c1->window()
456 && c2->wmClientLeader() != c2->window())
460 else if( c1->pid() != c2->pid()
461 || c1->wmClientMachine(
false ) != c2->wmClientMachine(
false ))
463 else if( c1->wmClientLeader() != c2->wmClientLeader()
464 && c1->wmClientLeader() != c1->window()
465 && c2->wmClientLeader() != c2->window())
467 else if( !resourceMatch( c1, c2 ))
469 else if( !sameAppWindowRoleMatch( c1, c2, active_hack ))
471 else if( c1->pid() == 0 || c2->pid() == 0 )
490 bool Client::sameAppWindowRoleMatch(
const Client* c1,
const Client* c2,
bool active_hack )
492 if( c1->isTransient())
494 while( c1->transientFor() != NULL )
495 c1 = c1->transientFor();
496 if( c1->groupTransient())
497 return c1->group() == c2->group();
502 || c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
505 if( c2->isTransient())
507 while( c2->transientFor() != NULL )
508 c2 = c2->transientFor();
509 if( c2->groupTransient())
510 return c1->group() == c2->group();
512 || c1->group()->leaderClient() == c1 || c2->group()->leaderClient() == c2;
515 int pos1 = c1->windowRole().find(
'#' );
516 int pos2 = c2->windowRole().find(
'#' );
517 if(( pos1 >= 0 && pos2 >= 0 )
521 ((c1->resourceName() ==
"mozilla") && (c2->resourceName() ==
"mozilla")) )
525 if( !c1->isActive() && !c2->isActive())
579 void Client::readTransient()
581 TRANSIENCY_CHECK(
this );
582 Window new_transient_for_id;
583 if( XGetTransientForHint( tqt_xdisplay(), window(), &new_transient_for_id ))
585 original_transient_for_id = new_transient_for_id;
586 new_transient_for_id = verifyTransientFor( new_transient_for_id,
true );
590 original_transient_for_id = None;
591 new_transient_for_id = verifyTransientFor( None,
false );
593 setTransient( new_transient_for_id );
596 void Client::setTransient( Window new_transient_for_id )
598 TRANSIENCY_CHECK(
this );
599 if( new_transient_for_id != transient_for_id )
601 removeFromMainClients();
602 transient_for = NULL;
603 transient_for_id = new_transient_for_id;
604 if( transient_for_id != None && !groupTransient())
606 transient_for = workspace()->findClient( WindowMatchPredicate( transient_for_id ));
607 assert( transient_for != NULL );
608 transient_for->addTransient(
this );
610 checkGroup( NULL,
true );
612 workspace()->updateCurrentTopMenu();
613 workspace()->updateClientLayer(
this );
617 void Client::removeFromMainClients()
619 TRANSIENCY_CHECK(
this );
620 if( transientFor() != NULL )
621 transientFor()->removeTransient(
this );
622 if( groupTransient())
624 for( ClientList::ConstIterator it = group()->members().begin();
625 it != group()->members().end();
627 (*it)->removeTransient(
this );
635 void Client::cleanGrouping()
637 TRANSIENCY_CHECK(
this );
649 removeFromMainClients();
660 for( ClientList::ConstIterator it = transients_list.begin();
661 it != transients_list.end();
664 if( (*it)->transientFor() == this )
666 ClientList::ConstIterator it2 = it++;
667 removeTransient( *it2 );
687 ClientList group_members = group()->members();
688 group()->removeMember(
this );
690 for( ClientList::ConstIterator it = group_members.begin();
691 it != group_members.end();
693 (*it)->removeTransient(
this );
705 void Client::checkGroupTransients()
707 TRANSIENCY_CHECK(
this );
708 for( ClientList::ConstIterator it1 = group()->members().begin();
709 it1 != group()->members().end();
712 if( !(*it1)->groupTransient())
714 for( ClientList::ConstIterator it2 = group()->members().begin();
715 it2 != group()->members().end();
720 for(
Client* cl = (*it2)->transientFor();
722 cl = cl->transientFor())
726 (*it2)->transients_list.remove( *it1 );
734 if( (*it2)->groupTransient() && (*it1)->hasTransient( *it2,
true ) && (*it2)->hasTransient( *it1,
true ))
735 (*it2)->transients_list.remove( *it1 );
741 for( ClientList::ConstIterator it3 = group()->members().begin();
742 it3 != group()->members().end();
745 if( *it1 == *it2 || *it2 == *it3 || *it1 == *it3 )
747 if( (*it2)->hasTransient( *it1,
false ) && (*it3)->hasTransient( *it1,
false ))
749 if( (*it2)->hasTransient( *it3,
true ))
750 (*it2)->transients_list.remove( *it1 );
751 if( (*it3)->hasTransient( *it2,
true ))
752 (*it3)->transients_list.remove( *it1 );
762 Window Client::verifyTransientFor( Window new_transient_for,
bool defined )
764 Window new_property_value = new_transient_for;
767 if( isSplash() && new_transient_for == None )
768 new_transient_for = workspace()->rootWin();
769 if( new_transient_for == None )
771 new_property_value = new_transient_for = workspace()->rootWin();
774 if( new_transient_for == window())
776 kdWarning( 1216 ) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to itself." << endl;
777 new_property_value = new_transient_for = workspace()->rootWin();
782 WId before_search = new_transient_for;
783 while( new_transient_for != None
784 && new_transient_for != workspace()->rootWin()
785 && !workspace()->findClient( WindowMatchPredicate( new_transient_for )))
787 Window root_return, parent_return;
790 int r = XQueryTree(tqt_xdisplay(), new_transient_for, &root_return, &parent_return, &wins, &nwins);
792 XFree((
void *) wins);
795 new_transient_for = parent_return;
797 if(
Client* new_transient_for_client = workspace()->findClient( WindowMatchPredicate( new_transient_for )))
799 if( new_transient_for != before_search )
801 kdDebug( 1212 ) <<
"Client " <<
this <<
" has WM_TRANSIENT_FOR poiting to non-toplevel window "
802 << before_search <<
", child of " << new_transient_for_client <<
", adjusting." << endl;
803 new_property_value = new_transient_for;
807 new_transient_for = before_search;
812 Window loop_pos = new_transient_for;
813 while( loop_pos != None && loop_pos != workspace()->rootWin())
815 Client* pos = workspace()->findClient( WindowMatchPredicate( loop_pos ));
818 loop_pos = pos->transient_for_id;
819 if( --count == 0 || pos ==
this )
821 kdWarning( 1216 ) <<
"Client " <<
this <<
" caused WM_TRANSIENT_FOR loop." << endl;
822 new_transient_for = workspace()->rootWin();
825 if( new_transient_for != workspace()->rootWin()
826 && workspace()->findClient( WindowMatchPredicate( new_transient_for )) == NULL )
828 new_transient_for = workspace()->rootWin();
830 if( new_property_value != original_transient_for_id )
831 XSetTransientForHint( tqt_xdisplay(), window(), new_property_value );
832 return new_transient_for;
835 void Client::addTransient( Client* cl )
837 TRANSIENCY_CHECK(
this );
838 assert( !transients_list.contains( cl ));
840 assert( cl !=
this );
841 transients_list.append( cl );
842 if( workspace()->mostRecentlyActivatedClient() ==
this && cl->isModal())
843 check_active_modal =
true;
852 void Client::removeTransient( Client* cl )
854 TRANSIENCY_CHECK(
this );
857 transients_list.remove( cl );
860 if( cl->transientFor() == this )
862 cl->transient_for_id = None;
863 cl->transient_for = NULL;
865 cl->setTransient( None );
870 void Client::checkTransient( Window w )
872 TRANSIENCY_CHECK(
this );
873 if( original_transient_for_id != w )
875 w = verifyTransientFor( w,
true );
881 bool Client::hasTransient(
const Client* cl,
bool indirect )
const
885 return hasTransientInternal( cl, indirect,
set );
888 bool Client::hasTransientInternal(
const Client* cl,
bool indirect, ConstClientList&
set )
const
890 if( cl->transientFor() != NULL )
892 if( cl->transientFor() == this )
896 if(
set.contains( cl ))
899 return hasTransientInternal( cl->transientFor(), indirect, set );
901 if( !cl->isTransient())
903 if( group() != cl->group())
906 if( transients().contains( const_cast< Client* >( cl )))
910 if(
set.contains(
this ))
913 for( ClientList::ConstIterator it = transients().begin();
914 it != transients().end();
916 if( (*it)->hasTransientInternal( cl, indirect,
set ))
921 ClientList Client::mainClients()
const
925 if( transientFor() != NULL )
926 return ClientList() <<
const_cast< Client*
>( transientFor());
928 for( ClientList::ConstIterator it = group()->members().begin();
929 it != group()->members().end();
931 if((*it)->hasTransient(
this,
false ))
932 result.append( *it );
936 Client* Client::findModal()
938 for( ClientList::ConstIterator it = transients().begin();
939 it != transients().end();
941 if(
Client* ret = (*it)->findModal())
951 void Client::checkGroup( Group* set_group,
bool force )
953 TRANSIENCY_CHECK(
this );
954 Group* old_group = in_group;
955 if( old_group != NULL )
957 if( set_group != NULL )
959 if( set_group != in_group )
961 if( in_group != NULL )
962 in_group->removeMember(
this );
963 in_group = set_group;
964 in_group->addMember(
this );
967 else if( window_group != None )
969 Group* new_group = workspace()->findGroup( window_group );
970 if( transientFor() != NULL && transientFor()->group() != new_group )
973 new_group = transientFor()->group();
975 if( new_group == NULL )
976 new_group =
new Group( window_group, workspace());
977 if( new_group != in_group )
979 if( in_group != NULL )
980 in_group->removeMember(
this );
981 in_group = new_group;
982 in_group->addMember(
this );
987 if( transientFor() != NULL )
990 Group* new_group = transientFor()->group();
991 if( new_group != in_group )
993 if( in_group != NULL )
994 in_group->removeMember(
this );
995 in_group = transientFor()->group();
996 in_group->addMember(
this );
999 else if( groupTransient())
1002 Group* new_group = workspace()->findClientLeaderGroup(
this );
1003 if( new_group == NULL )
1004 new_group =
new Group( None, workspace());
1005 if( new_group != in_group )
1007 if( in_group != NULL )
1008 in_group->removeMember(
this );
1009 in_group = new_group;
1010 in_group->addMember(
this );
1017 Group* new_group = workspace()->findClientLeaderGroup(
this );
1018 if( in_group != NULL && in_group != new_group )
1020 in_group->removeMember(
this );
1023 if( new_group == NULL )
1024 new_group =
new Group( None, workspace() );
1025 if( in_group != new_group )
1027 in_group = new_group;
1028 in_group->addMember(
this );
1032 if( in_group != old_group || force )
1034 for( ClientList::Iterator it = transients_list.begin();
1035 it != transients_list.end();
1038 if( (*it)->groupTransient() && (*it)->group() != group())
1039 it = transients_list.remove( it );
1043 if( groupTransient())
1046 if( old_group != NULL )
1048 for( ClientList::ConstIterator it = old_group->members().begin();
1049 it != old_group->members().end();
1051 (*it)->removeTransient(
this );
1054 for( ClientList::ConstIterator it = group()->members().begin();
1055 it != group()->members().end();
1060 (*it)->addTransient(
this );
1065 for( ClientList::ConstIterator it = group()->members().begin();
1066 it != group()->members().end();
1069 if( !(*it)->isSplash())
1071 if( !(*it)->groupTransient())
1073 if( *it ==
this || hasTransient( *it,
true ))
1075 addTransient( *it );
1078 if( old_group != NULL )
1080 checkGroupTransients();
1082 workspace()->updateClientLayer(
this );
1086 void Client::changeClientLeaderGroup( Group* gr )
1089 if( transientFor() != NULL )
1097 bool Client::check_active_modal =
false;
1099 void Client::checkActiveModal()
1104 Client* check_modal = workspace()->mostRecentlyActivatedClient();
1105 if( check_modal != NULL && check_modal->check_active_modal )
1107 Client* new_modal = check_modal->findModal();
1108 if( new_modal != NULL && new_modal != check_modal )
1110 if( !new_modal->isManaged())
1112 workspace()->activateClient( new_modal );
1114 check_modal->check_active_modal =
false;