From 508178e0d1e2b0e446502ddcb18c0d067d1a1718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Wed, 13 Dec 2006 18:48:58 +0000 Subject: [PATCH] Add checking code to detect inconsistencies of internal structures for window relations, like #117677. svn path=/trunk/KDE/kdebase/workspace/; revision=613274 --- client.h | 2 + group.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++ workspace.h | 81 +++++++------------------------------- 3 files changed, 127 insertions(+), 66 deletions(-) diff --git a/client.h b/client.h index cb8d659176..4c03fbe5ee 100644 --- a/client.h +++ b/client.h @@ -520,6 +520,8 @@ class Client : public QObject, public KDecorationDefines void show() { assert( false ); } // SELI remove after Client is no longer QWidget void hide() { assert( false ); } QTimer* demandAttentionKNotifyTimer; + + friend bool performTransiencyCheck(); }; // helper for Client::postponeGeometryUpdates() being called in pairs (true/false) diff --git a/group.cpp b/group.cpp index 0b2370881d..39caf08ac4 100644 --- a/group.cpp +++ b/group.cpp @@ -36,6 +36,103 @@ License. See the file "COPYING" for the exact licensing terms. namespace KWinInternal { +/* + Consistency checks for window relations. Since transients are determinated + using Client::transiency_list and main windows are determined using Client::transientFor() + or the group for group transients, these have to match both ways. +*/ +//#define ENABLE_TRANSIENCY_CHECK + +#ifdef NDEBUG +#undef ENABLE_TRANSIENCY_CHECK +#endif + +#ifdef ENABLE_TRANSIENCY_CHECK +bool performTransiencyCheck() + { + bool ret = true; + ClientList clients = Workspace::self()->clients; + for( ClientList::ConstIterator it1 = clients.begin(); + it1 != clients.end(); + ++it1 ) + { + if( (*it1)->deleting ) + continue; + if( !(*it1)->isTransient()) + { + if( !(*it1)->mainClients().isEmpty()) + { + kdDebug() << "TC: " << *it1 << " is not transient, has main clients:" << (*it1)->mainClients() << endl; + ret = false; + } + } + else + { + ClientList mains = (*it1)->mainClients(); + for( ClientList::ConstIterator it2 = mains.begin(); + it2 != mains.end(); + ++it2 ) + { + if( !(*it2)->transients_list.contains( *it1 )) + { + kdDebug() << "TC:" << *it1 << " has main client " << *it2 << " but main client does not have it as a transient" << endl; + ret = false; + } + } + } + ClientList trans = (*it1)->transients_list; + for( ClientList::ConstIterator it2 = trans.begin(); + it2 != trans.end(); + ++it2 ) + { + if( !(*it2)->mainClients().contains( *it1 )) + { + kdDebug() << "TC:" << *it1 << " has transient " << *it2 << " but transient does not have it as a main client" << endl; + ret = false; + } + } + } + return ret; + } + +static QString transiencyCheckStartBt; +static const Client* transiencyCheckClient; +static int transiencyCheck = 0; +static void startTransiencyCheck( const QString& bt, const Client* c ) + { + if( ++transiencyCheck == 1 ) + { + transiencyCheckStartBt = bt; + transiencyCheckClient = c; + } + } +static void checkTransiency() + { + if( --transiencyCheck == 0 ) + { + if( !performTransiencyCheck()) + { + kdDebug() << "BT:" << transiencyCheckStartBt << endl; + kdDebug() << "CLIENT:" << transiencyCheckClient << endl; + assert( false ); + } + } + } +class TransiencyChecker + { + public: + TransiencyChecker( const QString& bt, const Client*c ) { startTransiencyCheck( bt, c ); } + ~TransiencyChecker() { checkTransiency(); } + }; + +#define TRANSIENCY_CHECK( c ) TransiencyChecker transiency_checker( kdBacktrace(), c ) + +#else + +#define TRANSIENCY_CHECK( c ) + +#endif + //******************************************** // Group //******************************************** @@ -90,6 +187,7 @@ QPixmap Group::miniIcon() const void Group::addMember( Client* member_P ) { + TRANSIENCY_CHECK( member_P ); _members.append( member_P ); // kDebug() << "GROUPADD:" << this << ":" << member_P << endl; // kDebug() << kBacktrace() << endl; @@ -97,6 +195,7 @@ void Group::addMember( Client* member_P ) void Group::removeMember( Client* member_P ) { + TRANSIENCY_CHECK( member_P ); // kDebug() << "GROUPREMOVE:" << this << ":" << member_P << endl; // kDebug() << kBacktrace() << endl; Q_ASSERT( _members.contains( member_P )); @@ -149,6 +248,7 @@ Group* Workspace::findGroup( Window leader ) const // group with windows with the same client leader. Group* Workspace::findClientLeaderGroup( const Client* c ) const { + TRANSIENCY_CHECK( c ); Group* ret = NULL; for( ClientList::ConstIterator it = clients.begin(); it != clients.end(); @@ -233,6 +333,7 @@ void Workspace::updateOnAllDesktopsOfTransients( Client* c ) // A new window has been mapped. Check if it's not a mainwindow for some already existing transient window. void Workspace::checkTransients( Window w ) { + TRANSIENCY_CHECK( NULL ); for( ClientList::ConstIterator it = clients.begin(); it != clients.end(); ++it ) @@ -398,6 +499,7 @@ bool Client::sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool ac void Client::readTransient() { + TRANSIENCY_CHECK( this ); Window new_transient_for_id; if( XGetTransientForHint( display(), window(), &new_transient_for_id )) { @@ -414,6 +516,7 @@ void Client::readTransient() void Client::setTransient( Window new_transient_for_id ) { + TRANSIENCY_CHECK( this ); if( new_transient_for_id != transient_for_id ) { removeFromMainClients(); @@ -434,6 +537,7 @@ void Client::setTransient( Window new_transient_for_id ) void Client::removeFromMainClients() { + TRANSIENCY_CHECK( this ); if( transientFor() != NULL ) transientFor()->removeTransient( this ); if( groupTransient()) @@ -451,6 +555,7 @@ void Client::removeFromMainClients() // related lists. void Client::cleanGrouping() { + TRANSIENCY_CHECK( this ); // kDebug() << "CLEANGROUPING:" << this << endl; // for( ClientList::ConstIterator it = group()->members().begin(); // it != group()->members().end(); @@ -520,6 +625,7 @@ void Client::cleanGrouping() // Non-group transients not causing loops are checked in verifyTransientFor(). void Client::checkGroupTransients() { + TRANSIENCY_CHECK( this ); for( ClientList::ConstIterator it1 = group()->members().begin(); it1 != group()->members().end(); ++it1 ) @@ -649,6 +755,7 @@ Window Client::verifyTransientFor( Window new_transient_for, bool defined ) void Client::addTransient( Client* cl ) { + TRANSIENCY_CHECK( this ); assert( !transients_list.contains( cl )); // assert( !cl->hasTransient( this, true )); will be fixed in checkGroupTransients() assert( cl != this ); @@ -665,6 +772,7 @@ void Client::addTransient( Client* cl ) void Client::removeTransient( Client* cl ) { + TRANSIENCY_CHECK( this ); // kDebug() << "REMOVETRANS:" << this << ":" << cl << endl; // kDebug() << kBacktrace() << endl; transients_list.removeAll( cl ); @@ -682,6 +790,7 @@ void Client::removeTransient( Client* cl ) // A new window has been mapped. Check if it's not a mainwindow for this already existing window. void Client::checkTransient( Window w ) { + TRANSIENCY_CHECK( this ); if( original_transient_for_id != w ) return; w = verifyTransientFor( w, true ); @@ -762,6 +871,7 @@ Client* Client::findModal() // Argument is only when some specific group needs to be set. void Client::checkGroup( Group* set_group, bool force ) { + TRANSIENCY_CHECK( this ); Group* old_group = in_group; if( set_group != NULL ) { diff --git a/workspace.h b/workspace.h index b09166614c..4e41f4e799 100644 --- a/workspace.h +++ b/workspace.h @@ -18,8 +18,6 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include -#include -#include #include "utils.h" #include "kdecoration.h" @@ -79,7 +77,7 @@ class Workspace : public QObject, public KDecorationDefines virtual ~Workspace(); static Workspace * self() { return _self; } - + bool workspaceEvent( XEvent * ); KDecoration* createDecoration( KDecorationBridge* bridge ); @@ -89,9 +87,6 @@ class Workspace : public QObject, public KDecorationDefines template< typename T > Client* findClient( T predicate ); template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate ); template< typename T > void forEachClient( T procedure ); - template< typename T > Unmanaged* findUnmanaged( T predicate ); - template< typename T1, typename T2 > void forEachUnmanaged( T1 procedure, T2 predicate ); - template< typename T > void forEachUnmanaged( T procedure ); QRect clientArea( clientAreaOption, const QPoint& p, int desktop ) const; QRect clientArea( clientAreaOption, const Client* c ) const; @@ -186,7 +181,7 @@ class Workspace : public QObject, public KDecorationDefines ClientList ensureStackingOrder( const ClientList& clients ) const; - Client* topClientOnDesktop( int desktop, bool unconstrained = false ) const; + Client* topClientOnDesktop( int desktop, bool unconstrained = false, bool only_normal = true ) const; Client* findDesktop( bool topmost, int desktop ) const; void sendClientToDesktop( Client* c, int desktop, bool dont_activate ); void windowToPreviousDesktop( Client* c ); @@ -247,9 +242,6 @@ class Workspace : public QObject, public KDecorationDefines void removeGroup( Group* group, allowed_t ); Group* findClientLeaderGroup( const Client* c ) const; - // only called from Unmanaged::release() - void removeUnmanaged( Unmanaged*, allowed_t ); - bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data ); void focusToNull(); // SELI public? @@ -284,17 +276,6 @@ class Workspace : public QObject, public KDecorationDefines void requestDelayFocus( Client* ); void toggleTopDockShadows(bool on); - - void addDamage( const QRect& r ); - void addDamage( int x, int y, int w, int h ); - void addDamageFull(); - // creates XComposite overlay window, cal initOverlay() afterwards - bool createOverlay(); - // init overlay and the destination window in it - void setupOverlay( Window window ); - // destroys XComposite overlay window - void destroyOverlay(); - Window overlayWindow(); public slots: void refresh(); @@ -425,10 +406,11 @@ class Workspace : public QObject, public KDecorationDefines void cleanupTemporaryRules(); void writeWindowRules(); void slotBlockShortcuts(int data); - void setPopupClientOpacity( QAction* action ); - void setupCompositing(); - void performCompositing(); - void lostCMSelection(); + // kompmgr + void setPopupClientOpacity(int v); + void resetClientOpacity(); + void setTransButtonText(int value); + // end protected: bool keyPressMouseEmulation( XKeyEvent& ev ); @@ -476,8 +458,6 @@ class Workspace : public QObject, public KDecorationDefines // this is the right way to create a new client Client* createClient( Window w, bool is_mapped ); void addClient( Client* c, allowed_t ); - Unmanaged* createUnmanaged( Window w ); - void addUnmanaged( Unmanaged* c, allowed_t ); Window findSpecialEventWindow( XEvent* e ); @@ -519,8 +499,6 @@ class Workspace : public QObject, public KDecorationDefines void closeActivePopup(); void updateClientArea( bool force ); - - void finishCompositing(); SystemTrayWindowList systemTrayWins; @@ -557,11 +535,10 @@ class Workspace : public QObject, public KDecorationDefines ClientList clients; ClientList desktops; - UnmanagedList unmanaged; - ClientList unconstrained_stacking_order; - ClientList stacking_order; - QVector< ClientList > focus_chain; + ClientList unconstrained_stacking_order; // topmost last + ClientList stacking_order; // topmost last + QVector< ClientList > focus_chain; // currently ative last ClientList global_focus_chain; // this one is only for things like tabbox's MRU ClientList should_get_focus; // last is most recent ClientList attention_chain; @@ -595,7 +572,6 @@ class Workspace : public QObject, public KDecorationDefines QMenu *popup; QMenu *advanced_popup; - QMenu *trans_popup; QMenu *desk_popup; int desk_popup_index; @@ -679,14 +655,12 @@ class Workspace : public QObject, public KDecorationDefines bool forced_global_mouse_grab; friend class StackingUpdatesBlocker; - KSelectionOwner* cm_selection; - QTimer compositeTimer; - QTime lastCompositePaint; - int compositeRate; - QRegion damage_region; - Window overlay; // XComposite overlay window + //kompmgr QSlider *transSlider; QPushButton *transButton; + + private: + friend bool performTransiencyCheck(); }; // helper for Workspace::blockStackingUpdates() being called in pairs (true/false) @@ -829,11 +803,6 @@ inline bool Workspace::globalShortcutsDisabled() const return global_shortcuts_disabled || global_shortcuts_disabled_for_client; } -inline Window Workspace::overlayWindow() - { - return overlay; - } - template< typename T > inline Client* Workspace::findClient( T predicate ) { @@ -861,27 +830,7 @@ inline void Workspace::forEachClient( T procedure ) return forEachClient( procedure, TruePredicate()); } -template< typename T > -inline Unmanaged* Workspace::findUnmanaged( T predicate ) - { - return findUnmanagedInList( unmanaged, predicate ); - } - -template< typename T1, typename T2 > -inline void Workspace::forEachUnmanaged( T1 procedure, T2 predicate ) - { - for ( UnmanagedList::ConstIterator it = unmanaged.begin(); it != unmanaged.end(); ++it) - if ( predicate( const_cast< const Unmanaged* >( *it))) - procedure( *it ); - } - -template< typename T > -inline void Workspace::forEachUnmanaged( T procedure ) - { - return forEachUnmanaged( procedure, TruePredicate()); - } - -KWIN_COMPARE_PREDICATE( ClientMatchPredicate, Client, const Client*, cl == value ); +KWIN_COMPARE_PREDICATE( ClientMatchPredicate, const Client*, cl == value ); inline bool Workspace::hasClient( const Client* c ) { return findClient( ClientMatchPredicate( c ));