diff --git a/client.cpp b/client.cpp index 30b3ebdad8..c39619f1d4 100644 --- a/client.cpp +++ b/client.cpp @@ -225,7 +225,7 @@ void Client::destroyClient() deleteClient( this, Allowed ); } -void Client::updateDecoration( bool check_workspace_pos, bool force, bool delay_delete ) +void Client::updateDecoration( bool check_workspace_pos, bool force ) { if( !force && (( decoration == NULL && noBorder()) || ( decoration != NULL && !noBorder()))) @@ -233,7 +233,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force, bool delay_ bool do_show = false; ++block_geometry; if( force ) - destroyDecoration( delay_delete ); + destroyDecoration(); if( !noBorder()) { decoration = workspace()->createDecoration( bridge ); @@ -255,7 +255,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force, bool delay_ do_show = true; } else - destroyDecoration( delay_delete ); + destroyDecoration(); if( check_workspace_pos ) checkWorkspacePosition(); --block_geometry; @@ -265,21 +265,14 @@ void Client::updateDecoration( bool check_workspace_pos, bool force, bool delay_ updateFrameStrut(); } -void Client::destroyDecoration( bool delay_delete ) +void Client::destroyDecoration() { if( decoration != NULL ) { - // When selecting the noborder operation from the popup menu after clicking on the menu - // button, the decoration should be deleted. But after closing the popup, the flow - // of control is still in the decoration, and the decorations usually do - // "button->setDown( false )". Therefore, delay the actual deleting. - if( delay_delete ) - decoration->deleteLater(); - else - delete decoration; + delete decoration; + decoration = NULL; QPoint grav = calculateGravitation( true ); border_left = border_right = border_top = border_bottom = 0; - decoration = NULL; setMask( QRegion()); // reset shape mask int save_workarea_diff_x = workarea_diff_x; int save_workarea_diff_y = workarea_diff_y; @@ -395,7 +388,7 @@ void Client::setUserNoBorder( bool set ) if( user_noborder == set ) return; user_noborder = set; - updateDecoration( true, false, true ); // delayed deletion of decoration + updateDecoration( true, false ); } bool Client::grabInput() @@ -948,10 +941,7 @@ void Client::killWindow() killProcess( false ); // always kill this client at the server XKillClient(qt_xdisplay(), window() ); - // needs to be delayed, because this may be called from the client - // popup menu, and there may be possibly code still touching - // this instance after returning from killWindow() - QTimer::singleShot( 0, this, SLOT( destroyClient())); + destroyClient(); } // send a ping to the window using _NET_WM_PING if possible diff --git a/client.h b/client.h index 2a765c1b48..dc970a9cdc 100644 --- a/client.h +++ b/client.h @@ -180,7 +180,7 @@ class Client : public QObject, public KDecorationDefines void setMask( const QRegion& r, int mode = X::Unsorted ); - void updateDecoration( bool check_workspace_pos, bool force = false, bool delay_delete = false ); + void updateDecoration( bool check_workspace_pos, bool force = false ); void checkBorderSizes(); // shape extensions @@ -349,7 +349,7 @@ class Client : public QObject, public KDecorationDefines void embedClient( Window w ); void detectNoBorder(); - void destroyDecoration( bool delay_delete = false ); + void destroyDecoration(); void updateFrameStrut(); void rawShow(); // just shows it diff --git a/clients/b2/b2client.cpp b/clients/b2/b2client.cpp index 19454482c0..de926f2f5f 100644 --- a/clients/b2/b2client.cpp +++ b/clients/b2/b2client.cpp @@ -757,7 +757,10 @@ void B2Client::menuButtonPressed() { QPoint menupoint = button[BtnMenu]->mapToGlobal( button[BtnMenu]->rect().bottomLeft()); + KDecorationFactory* f = factory(); showWindowMenu(menupoint); + if( !f->exists( this )) // 'this' was destroyed + return; button[BtnMenu]->setDown(false); } diff --git a/clients/default/kdedefault.cpp b/clients/default/kdedefault.cpp index 6daff8d1b2..224f8c9f7f 100644 --- a/clients/default/kdedefault.cpp +++ b/clients/default/kdedefault.cpp @@ -1277,7 +1277,10 @@ void KDEDefaultClient::menuButtonPressed() QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1, button[BtnMenu]->rect().bottomLeft().y()+2 ); + KDecorationFactory* f = factory(); showWindowMenu( button[BtnMenu]->mapToGlobal( menupoint )); + if( !f->exists( this )) // 'this' was destroyed + return; button[BtnMenu]->setDown(false); } diff --git a/clients/keramik/keramik.cpp b/clients/keramik/keramik.cpp index 87e7a1d683..0faf299074 100644 --- a/clients/keramik/keramik.cpp +++ b/clients/keramik/keramik.cpp @@ -1314,7 +1314,10 @@ void KeramikClient::menuButtonPressed() { QPoint menuPoint ( button[MenuButton]->rect().bottomLeft().x() - 6, button[MenuButton]->rect().bottomLeft().y() + 3 ); + KDecorationFactory* f = factory(); showWindowMenu( button[MenuButton]->mapToGlobal( menuPoint )); + if( !f->exists( this )) // 'this' was destroyed + return; button[MenuButton]->setDown(false); } diff --git a/clients/quartz/quartz.cpp b/clients/quartz/quartz.cpp index 211fcd3bcb..ec7bc4f96a 100644 --- a/clients/quartz/quartz.cpp +++ b/clients/quartz/quartz.cpp @@ -971,7 +971,10 @@ void QuartzClient::menuButtonPressed() QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1, button[BtnMenu]->rect().bottomLeft().y()+2 ); menupoint = button[BtnMenu]->mapToGlobal( menupoint ); - showWindowMenu(menupoint); + KDecorationFactory* f = factory(); + showWindowMenu(menupoint); + if( !f->exists( this )) // 'this' was destroyed + return; button[BtnMenu]->setDown(false); } diff --git a/clients/redmond/redmond.cpp b/clients/redmond/redmond.cpp index 3af1053306..863ec815dc 100644 --- a/clients/redmond/redmond.cpp +++ b/clients/redmond/redmond.cpp @@ -819,7 +819,10 @@ void RedmondDeco::menuButtonPressed() if (!dbl) { QPoint menupoint(button[BtnMenu]->rect().bottomLeft().x()-3, button[BtnMenu]->rect().bottomLeft().y()+4); + KDecorationFactory* f = factory(); showWindowMenu(button[BtnMenu]->mapToGlobal(menupoint)); + if( !f->exists( this )) // 'this' was destroyed + return; button[BtnMenu]->setDown(false); } else { closeWindow(); diff --git a/geometry.cpp b/geometry.cpp index 12e01fe36c..c3c074ba8c 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -653,8 +653,7 @@ void Client::getWmNormalHints() long msize; if (XGetWMNormalHints(qt_xdisplay(), window(), &xSizeHint, &msize) == 0 ) xSizeHint.flags = 0; - // set defined values for basesize, minsize, maxsize, aspect and resizeinc, - // even if they're not in flags + // set defined values for the fields, even if they're not in flags // basesize is just like minsize, except for minsize is not used for aspect ratios // keep basesize only for aspect ratios, for size increments, keep the base @@ -696,7 +695,7 @@ void Client::getWmNormalHints() xSizeHint.max_aspect.x = INT_MAX; xSizeHint.max_aspect.y = 1; } - if( !xSizeHint.flags & PWinGravity ) + if( ! ( xSizeHint.flags & PWinGravity )) xSizeHint.win_gravity = NorthWestGravity; if( isManaged()) { // update to match restrictions @@ -1288,7 +1287,7 @@ void Client::setFullScreen( bool set, bool user ) StackingUpdatesBlocker blocker( workspace()); workspace()->updateClientLayer( this ); // active fullscreens get different layer info->setState( isFullScreen() ? NET::FullScreen : 0, NET::FullScreen ); - updateDecoration( false, false, true ); // delayed deletion of decoration + updateDecoration( false, false ); if( isFullScreen()) setGeometry( workspace()->clientArea( MaximizeFullArea, this )); else diff --git a/lib/kdecoration.h b/lib/kdecoration.h index 30e854779b..39af6e4204 100644 --- a/lib/kdecoration.h +++ b/lib/kdecoration.h @@ -366,9 +366,26 @@ class KDecoration */ QString caption() const; /** - * This function invokes the window operations menu. + * This function invokes the window operations menu. IMPORTANT: As a result + * of this function, the decoration object that called it may be destroyed + * after the function returns. This means that the decoration object must + * either return immediately after calling showWindowMenu(), or it must + * use KDecorationFactory::exists() to check it's still valid. For example, + * the code handling clicks on the menu button should look similarly like this: + * + * \code + * KDecorationFactory* f = factory(); // needs to be saved before + * showWindowMenu( button[MenuButton]->mapToGlobal( menuPoint )); + * if( !f->exists( this )) // destroyed, return immediately + * return; + * button[MenuButton]->setDown(false); + * \endcode */ void showWindowMenu( QPoint pos ); + /** + * This function performs the given window operation. This function may destroy + * the current decoration object, just like showWindowMenu(). + */ void performWindowOperation( WindowOperation op ); /** * If the decoration is non-rectangular, this function needs to be called @@ -571,6 +588,8 @@ class KDecoration * This function can be called by the decoration to request * closing of the decorated window. Note that closing the window * also involves destroying the decoration. + * IMPORTANT: This function may destroy the current decoration object, + * just like showWindowMenu(). */ void closeWindow(); /** diff --git a/lib/kdecorationfactory.cpp b/lib/kdecorationfactory.cpp index 555967443d..38cf41ba01 100644 --- a/lib/kdecorationfactory.cpp +++ b/lib/kdecorationfactory.cpp @@ -52,6 +52,11 @@ QValueList< KDecorationDefines::BorderSize > KDecorationFactory::borderSizes() c return QValueList< BorderSize >() << BorderNormal; } +bool KDecorationFactory::exists( const KDecoration* deco ) const + { + return _decorations.contains( const_cast< KDecoration* >( deco )); + } + void KDecorationFactory::addDecoration( KDecoration* deco ) { _decorations.append( deco ); diff --git a/lib/kdecorationfactory.h b/lib/kdecorationfactory.h index da04c1b810..f55f3058f2 100644 --- a/lib/kdecorationfactory.h +++ b/lib/kdecorationfactory.h @@ -77,6 +77,13 @@ class KDecorationFactory * configuration settings for the decoration. */ const KDecorationOptions* options(); // convenience + /** + * Returns true if the given decoration object still exists. This is necessary + * e.g. when calling KDecoration::showWindowMenu(), which may cause the decoration + * to be destroyed. Note that this function is reliable only if called immediately + * after such actions. + */ + bool exists( const KDecoration* deco ) const; /** * @internal */