Commit cc99fac3 authored by Aurélien Gâteau's avatar Aurélien Gâteau
Browse files

KCMultiDialog: Fix crash when clicking OK

When one closes KCMultiDialog with OK, QDialog::finished() can be emitted
before the clicked() signal of the OK button. This causes the following
sequence to happen:

- KCMultiDialogPrivate::_k_dialogClosed
  * deletes the KCModule
    - KCModuleProxyPrivate::_k_moduleDestroyed
      * sets kcm to 0

- KCMultiDialog::slotOkClicked
  - KCMultiDialogPrivate::apply
    - KCModuleProxy::save
      - KCModuleProxyPrivate::realModule
        * notices kcm is 0, so recreates it
        * calls kcm->save()
          - KWinDesktopConfig::save()
            * crashes because it expects kcm->load() to have been called

To avoid this, trigger the cleanup code in closeEvent() rather than when
finished() is emitted, as we can be sure closeEvent() is always called
*after* the methods connected to the button box signals has executed.

REVIEW: 118639
BUG: 334624
parent 2fb16ecf
......@@ -199,20 +199,6 @@ void KCMultiDialogPrivate::_k_updateHeader(bool use, const QString &message)
}
}
void KCMultiDialogPrivate::_k_dialogClosed()
{
// qDebug() ;
/**
* If we don't delete them, the DBUS registration stays, and trying to load the KCMs
* in other situations will lead to "module already loaded in Foo," while to the user
* doesn't appear so(the dialog is hidden)
*/
for (int i = 0; i < modules.count(); ++i) {
modules[ i ].kcm->deleteClient();
}
}
void KCMultiDialogPrivate::init()
{
Q_Q(KCMultiDialog);
......@@ -238,7 +224,6 @@ void KCMultiDialogPrivate::init()
q->setButtonBox(buttonBox);
q->connect(q, SIGNAL(finished(int)), SLOT(_k_dialogClosed()));
q->connect(q, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)),
SLOT(_k_slotCurrentPageChanged(KPageWidgetItem*,KPageWidgetItem*)));
......@@ -388,6 +373,21 @@ void KCMultiDialog::slotHelpClicked()
}
}
void KCMultiDialog::closeEvent(QCloseEvent *event)
{
Q_D(KCMultiDialog);
KPageDialog::closeEvent(event);
/**
* If we don't delete them, the DBUS registration stays, and trying to load the KCMs
* in other situations will lead to "module already loaded in Foo," while to the user
* doesn't appear so(the dialog is hidden)
*/
Q_FOREACH(auto &proxy, d->modules) {
proxy.kcm->deleteClient();
}
}
KPageWidgetItem *KCMultiDialog::addModule(const QString &path, const QStringList &args)
{
QString complete = path;
......
......@@ -126,6 +126,8 @@ protected:
KCMultiDialogPrivate *const d_ptr;
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
protected Q_SLOTS:
/**
* This slot is called when the user presses the "Default" Button.
......@@ -174,7 +176,6 @@ protected Q_SLOTS:
private:
Q_PRIVATE_SLOT(d_func(), void _k_slotCurrentPageChanged(KPageWidgetItem *, KPageWidgetItem *))
Q_PRIVATE_SLOT(d_func(), void _k_clientChanged())
Q_PRIVATE_SLOT(d_func(), void _k_dialogClosed())
Q_PRIVATE_SLOT(d_func(), void _k_updateHeader(bool use, const QString &message))
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment