Add checking code to detect inconsistencies of internal structures

for window relations, like #117677.


svn path=/trunk/KDE/kdebase/workspace/; revision=613274
icc-effect-5.14.5
Luboš Luňák 2006-12-13 18:48:58 +00:00
parent f57d89d597
commit 508178e0d1
3 changed files with 127 additions and 66 deletions

View File

@ -520,6 +520,8 @@ class Client : public QObject, public KDecorationDefines
void show() { assert( false ); } // SELI remove after Client is no longer QWidget void show() { assert( false ); } // SELI remove after Client is no longer QWidget
void hide() { assert( false ); } void hide() { assert( false ); }
QTimer* demandAttentionKNotifyTimer; QTimer* demandAttentionKNotifyTimer;
friend bool performTransiencyCheck();
}; };
// helper for Client::postponeGeometryUpdates() being called in pairs (true/false) // helper for Client::postponeGeometryUpdates() being called in pairs (true/false)

110
group.cpp
View File

@ -36,6 +36,103 @@ License. See the file "COPYING" for the exact licensing terms.
namespace KWinInternal 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 // Group
//******************************************** //********************************************
@ -90,6 +187,7 @@ QPixmap Group::miniIcon() const
void Group::addMember( Client* member_P ) void Group::addMember( Client* member_P )
{ {
TRANSIENCY_CHECK( member_P );
_members.append( member_P ); _members.append( member_P );
// kDebug() << "GROUPADD:" << this << ":" << member_P << endl; // kDebug() << "GROUPADD:" << this << ":" << member_P << endl;
// kDebug() << kBacktrace() << endl; // kDebug() << kBacktrace() << endl;
@ -97,6 +195,7 @@ void Group::addMember( Client* member_P )
void Group::removeMember( Client* member_P ) void Group::removeMember( Client* member_P )
{ {
TRANSIENCY_CHECK( member_P );
// kDebug() << "GROUPREMOVE:" << this << ":" << member_P << endl; // kDebug() << "GROUPREMOVE:" << this << ":" << member_P << endl;
// kDebug() << kBacktrace() << endl; // kDebug() << kBacktrace() << endl;
Q_ASSERT( _members.contains( member_P )); 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 with windows with the same client leader.
Group* Workspace::findClientLeaderGroup( const Client* c ) const Group* Workspace::findClientLeaderGroup( const Client* c ) const
{ {
TRANSIENCY_CHECK( c );
Group* ret = NULL; Group* ret = NULL;
for( ClientList::ConstIterator it = clients.begin(); for( ClientList::ConstIterator it = clients.begin();
it != clients.end(); 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. // A new window has been mapped. Check if it's not a mainwindow for some already existing transient window.
void Workspace::checkTransients( Window w ) void Workspace::checkTransients( Window w )
{ {
TRANSIENCY_CHECK( NULL );
for( ClientList::ConstIterator it = clients.begin(); for( ClientList::ConstIterator it = clients.begin();
it != clients.end(); it != clients.end();
++it ) ++it )
@ -398,6 +499,7 @@ bool Client::sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool ac
void Client::readTransient() void Client::readTransient()
{ {
TRANSIENCY_CHECK( this );
Window new_transient_for_id; Window new_transient_for_id;
if( XGetTransientForHint( display(), 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 ) void Client::setTransient( Window new_transient_for_id )
{ {
TRANSIENCY_CHECK( this );
if( new_transient_for_id != transient_for_id ) if( new_transient_for_id != transient_for_id )
{ {
removeFromMainClients(); removeFromMainClients();
@ -434,6 +537,7 @@ void Client::setTransient( Window new_transient_for_id )
void Client::removeFromMainClients() void Client::removeFromMainClients()
{ {
TRANSIENCY_CHECK( this );
if( transientFor() != NULL ) if( transientFor() != NULL )
transientFor()->removeTransient( this ); transientFor()->removeTransient( this );
if( groupTransient()) if( groupTransient())
@ -451,6 +555,7 @@ void Client::removeFromMainClients()
// related lists. // related lists.
void Client::cleanGrouping() void Client::cleanGrouping()
{ {
TRANSIENCY_CHECK( this );
// kDebug() << "CLEANGROUPING:" << this << endl; // kDebug() << "CLEANGROUPING:" << this << endl;
// for( ClientList::ConstIterator it = group()->members().begin(); // for( ClientList::ConstIterator it = group()->members().begin();
// it != group()->members().end(); // it != group()->members().end();
@ -520,6 +625,7 @@ void Client::cleanGrouping()
// Non-group transients not causing loops are checked in verifyTransientFor(). // Non-group transients not causing loops are checked in verifyTransientFor().
void Client::checkGroupTransients() void Client::checkGroupTransients()
{ {
TRANSIENCY_CHECK( this );
for( ClientList::ConstIterator it1 = group()->members().begin(); for( ClientList::ConstIterator it1 = group()->members().begin();
it1 != group()->members().end(); it1 != group()->members().end();
++it1 ) ++it1 )
@ -649,6 +755,7 @@ Window Client::verifyTransientFor( Window new_transient_for, bool defined )
void Client::addTransient( Client* cl ) void Client::addTransient( Client* cl )
{ {
TRANSIENCY_CHECK( this );
assert( !transients_list.contains( cl )); assert( !transients_list.contains( cl ));
// assert( !cl->hasTransient( this, true )); will be fixed in checkGroupTransients() // assert( !cl->hasTransient( this, true )); will be fixed in checkGroupTransients()
assert( cl != this ); assert( cl != this );
@ -665,6 +772,7 @@ void Client::addTransient( Client* cl )
void Client::removeTransient( Client* cl ) void Client::removeTransient( Client* cl )
{ {
TRANSIENCY_CHECK( this );
// kDebug() << "REMOVETRANS:" << this << ":" << cl << endl; // kDebug() << "REMOVETRANS:" << this << ":" << cl << endl;
// kDebug() << kBacktrace() << endl; // kDebug() << kBacktrace() << endl;
transients_list.removeAll( cl ); 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. // A new window has been mapped. Check if it's not a mainwindow for this already existing window.
void Client::checkTransient( Window w ) void Client::checkTransient( Window w )
{ {
TRANSIENCY_CHECK( this );
if( original_transient_for_id != w ) if( original_transient_for_id != w )
return; return;
w = verifyTransientFor( w, true ); w = verifyTransientFor( w, true );
@ -762,6 +871,7 @@ Client* Client::findModal()
// Argument is only when some specific group needs to be set. // Argument is only when some specific group needs to be set.
void Client::checkGroup( Group* set_group, bool force ) void Client::checkGroup( Group* set_group, bool force )
{ {
TRANSIENCY_CHECK( this );
Group* old_group = in_group; Group* old_group = in_group;
if( set_group != NULL ) if( set_group != NULL )
{ {

View File

@ -18,8 +18,6 @@ License. See the file "COPYING" for the exact licensing terms.
#include <QCursor> #include <QCursor>
#include <netwm.h> #include <netwm.h>
#include <kxmessages.h> #include <kxmessages.h>
#include <qdatetime.h>
#include <kmanagerselection.h>
#include "utils.h" #include "utils.h"
#include "kdecoration.h" #include "kdecoration.h"
@ -79,7 +77,7 @@ class Workspace : public QObject, public KDecorationDefines
virtual ~Workspace(); virtual ~Workspace();
static Workspace * self() { return _self; } static Workspace * self() { return _self; }
bool workspaceEvent( XEvent * ); bool workspaceEvent( XEvent * );
KDecoration* createDecoration( KDecorationBridge* bridge ); KDecoration* createDecoration( KDecorationBridge* bridge );
@ -89,9 +87,6 @@ class Workspace : public QObject, public KDecorationDefines
template< typename T > Client* findClient( T predicate ); template< typename T > Client* findClient( T predicate );
template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate ); template< typename T1, typename T2 > void forEachClient( T1 procedure, T2 predicate );
template< typename T > void forEachClient( T procedure ); 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 QPoint& p, int desktop ) const;
QRect clientArea( clientAreaOption, const Client* c ) const; QRect clientArea( clientAreaOption, const Client* c ) const;
@ -186,7 +181,7 @@ class Workspace : public QObject, public KDecorationDefines
ClientList ensureStackingOrder( const ClientList& clients ) const; 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; Client* findDesktop( bool topmost, int desktop ) const;
void sendClientToDesktop( Client* c, int desktop, bool dont_activate ); void sendClientToDesktop( Client* c, int desktop, bool dont_activate );
void windowToPreviousDesktop( Client* c ); void windowToPreviousDesktop( Client* c );
@ -247,9 +242,6 @@ class Workspace : public QObject, public KDecorationDefines
void removeGroup( Group* group, allowed_t ); void removeGroup( Group* group, allowed_t );
Group* findClientLeaderGroup( const Client* c ) const; Group* findClientLeaderGroup( const Client* c ) const;
// only called from Unmanaged::release()
void removeUnmanaged( Unmanaged*, allowed_t );
bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data ); bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data );
void focusToNull(); // SELI public? void focusToNull(); // SELI public?
@ -284,17 +276,6 @@ class Workspace : public QObject, public KDecorationDefines
void requestDelayFocus( Client* ); void requestDelayFocus( Client* );
void toggleTopDockShadows(bool on); 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: public slots:
void refresh(); void refresh();
@ -425,10 +406,11 @@ class Workspace : public QObject, public KDecorationDefines
void cleanupTemporaryRules(); void cleanupTemporaryRules();
void writeWindowRules(); void writeWindowRules();
void slotBlockShortcuts(int data); void slotBlockShortcuts(int data);
void setPopupClientOpacity( QAction* action ); // kompmgr
void setupCompositing(); void setPopupClientOpacity(int v);
void performCompositing(); void resetClientOpacity();
void lostCMSelection(); void setTransButtonText(int value);
// end
protected: protected:
bool keyPressMouseEmulation( XKeyEvent& ev ); bool keyPressMouseEmulation( XKeyEvent& ev );
@ -476,8 +458,6 @@ class Workspace : public QObject, public KDecorationDefines
// this is the right way to create a new client // this is the right way to create a new client
Client* createClient( Window w, bool is_mapped ); Client* createClient( Window w, bool is_mapped );
void addClient( Client* c, allowed_t ); void addClient( Client* c, allowed_t );
Unmanaged* createUnmanaged( Window w );
void addUnmanaged( Unmanaged* c, allowed_t );
Window findSpecialEventWindow( XEvent* e ); Window findSpecialEventWindow( XEvent* e );
@ -519,8 +499,6 @@ class Workspace : public QObject, public KDecorationDefines
void closeActivePopup(); void closeActivePopup();
void updateClientArea( bool force ); void updateClientArea( bool force );
void finishCompositing();
SystemTrayWindowList systemTrayWins; SystemTrayWindowList systemTrayWins;
@ -557,11 +535,10 @@ class Workspace : public QObject, public KDecorationDefines
ClientList clients; ClientList clients;
ClientList desktops; ClientList desktops;
UnmanagedList unmanaged;
ClientList unconstrained_stacking_order; ClientList unconstrained_stacking_order; // topmost last
ClientList stacking_order; ClientList stacking_order; // topmost last
QVector< ClientList > focus_chain; QVector< ClientList > focus_chain; // currently ative last
ClientList global_focus_chain; // this one is only for things like tabbox's MRU ClientList global_focus_chain; // this one is only for things like tabbox's MRU
ClientList should_get_focus; // last is most recent ClientList should_get_focus; // last is most recent
ClientList attention_chain; ClientList attention_chain;
@ -595,7 +572,6 @@ class Workspace : public QObject, public KDecorationDefines
QMenu *popup; QMenu *popup;
QMenu *advanced_popup; QMenu *advanced_popup;
QMenu *trans_popup;
QMenu *desk_popup; QMenu *desk_popup;
int desk_popup_index; int desk_popup_index;
@ -679,14 +655,12 @@ class Workspace : public QObject, public KDecorationDefines
bool forced_global_mouse_grab; bool forced_global_mouse_grab;
friend class StackingUpdatesBlocker; friend class StackingUpdatesBlocker;
KSelectionOwner* cm_selection; //kompmgr
QTimer compositeTimer;
QTime lastCompositePaint;
int compositeRate;
QRegion damage_region;
Window overlay; // XComposite overlay window
QSlider *transSlider; QSlider *transSlider;
QPushButton *transButton; QPushButton *transButton;
private:
friend bool performTransiencyCheck();
}; };
// helper for Workspace::blockStackingUpdates() being called in pairs (true/false) // 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; return global_shortcuts_disabled || global_shortcuts_disabled_for_client;
} }
inline Window Workspace::overlayWindow()
{
return overlay;
}
template< typename T > template< typename T >
inline Client* Workspace::findClient( T predicate ) inline Client* Workspace::findClient( T predicate )
{ {
@ -861,27 +830,7 @@ inline void Workspace::forEachClient( T procedure )
return forEachClient( procedure, TruePredicate()); return forEachClient( procedure, TruePredicate());
} }
template< typename T > KWIN_COMPARE_PREDICATE( ClientMatchPredicate, const Client*, cl == value );
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 );
inline bool Workspace::hasClient( const Client* c ) inline bool Workspace::hasClient( const Client* c )
{ {
return findClient( ClientMatchPredicate( c )); return findClient( ClientMatchPredicate( c ));