summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@digia.com>2013-09-06 14:46:49 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-09 14:49:27 +0200
commitc03d0a984682ce5cea5a5882bab0075318b18f08 (patch)
treeff68e7c62a119d83fa1fd7020f1e3be29fd6f8f1
parent42223a777e28f2e6884cfd5540618ba9b571954e (diff)
Windows: Use QSharedPointer for the dialog helpers.
The dialog thread can outlive the platform dialog helper if the helper is destroyed. In that case, IFileDialog::Show() returns since the parent window is destroyed and then tried to emit signals on the destroyed helper class instance. Pass a shared pointer to the native dialog instead of a pointer to the helper class to the dialog. Task-number: QTBUG-32494 Task-number: QTBUG-30513 Change-Id: I7c2e769460270a26d886fdefee93ea59c2a17196 Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp62
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.h7
2 files changed, 39 insertions, 30 deletions
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 745f6548b5..9f00412b4c 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -452,7 +452,8 @@ class QWindowsNativeDialogBase : public QObject
Q_OBJECT
public:
virtual void setWindowTitle(const QString &title) = 0;
- virtual void exec(HWND owner = 0) = 0;
+ bool executed() const { return m_executed; }
+ void exec(HWND owner = 0) { doExec(owner); m_executed = true; }
signals:
void accepted();
@@ -462,7 +463,12 @@ public slots:
virtual void close() = 0;
protected:
- QWindowsNativeDialogBase() {}
+ QWindowsNativeDialogBase() : m_executed(false) {}
+
+private:
+ virtual void doExec(HWND owner = 0) = 0;
+
+ bool m_executed;
};
/*!
@@ -492,18 +498,11 @@ QWindowsDialogHelperBase<BaseClass>::QWindowsDialogHelperBase() :
template <class BaseClass>
QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() const
{
- if (!m_nativeDialog) {
+ if (m_nativeDialog.isNull()) {
qWarning("%s invoked with no native dialog present.", __FUNCTION__);
return 0;
}
- return m_nativeDialog;
-}
-
-template <class BaseClass>
-void QWindowsDialogHelperBase<BaseClass>::deleteNativeDialog()
-{
- delete m_nativeDialog;
- m_nativeDialog = 0;
+ return m_nativeDialog.data();
}
template <class BaseClass>
@@ -515,10 +514,11 @@ void QWindowsDialogHelperBase<BaseClass>::timerEvent(QTimerEvent *)
template <class BaseClass>
QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialog()
{
- // Create dialog and apply common settings.
- if (!m_nativeDialog)
- m_nativeDialog = createNativeDialog();
- return m_nativeDialog;
+ // Create dialog and apply common settings. Check "executed" flag as well
+ // since for example IFileDialog::Show() works only once.
+ if (m_nativeDialog.isNull() || m_nativeDialog->executed())
+ m_nativeDialog = QWindowsNativeDialogBasePtr(createNativeDialog());
+ return m_nativeDialog.data();
}
/*!
@@ -533,18 +533,22 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialo
class QWindowsDialogThread : public QThread
{
public:
- QWindowsDialogThread(QPlatformDialogHelper *h) : m_helper(h) {}
+ typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr;
+
+ explicit QWindowsDialogThread(const QWindowsNativeDialogBasePtr &d, HWND owner)
+ : m_dialog(d), m_owner(owner) {}
void run();
private:
- QPlatformDialogHelper *m_helper;
+ const QWindowsNativeDialogBasePtr m_dialog;
+ const HWND m_owner;
};
void QWindowsDialogThread::run()
{
if (QWindowsContext::verboseDialogs)
qDebug(">%s" , __FUNCTION__);
- m_helper->exec();
+ m_dialog->exec(m_owner);
deleteLater();
if (QWindowsContext::verboseDialogs)
qDebug("<%s" , __FUNCTION__);
@@ -563,7 +567,7 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags,
}
if (QWindowsContext::verboseDialogs)
qDebug("%s modal=%d native=%p parent=%p" ,
- __FUNCTION__, modal, m_nativeDialog, m_ownerWindow);
+ __FUNCTION__, modal, m_nativeDialog.data(), m_ownerWindow);
if (!modal && !supportsNonModalDialog(parent))
return false; // Was it changed in-between?
if (!ensureNativeDialog())
@@ -583,7 +587,8 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags,
template <class BaseClass>
void QWindowsDialogHelperBase<BaseClass>::startDialogThread()
{
- QWindowsDialogThread *thread = new QWindowsDialogThread(this);
+ Q_ASSERT(!m_nativeDialog.isNull());
+ QWindowsDialogThread *thread = new QWindowsDialogThread(m_nativeDialog, m_ownerWindow);
thread->start();
stopTimer();
}
@@ -613,7 +618,7 @@ void QWindowsDialogHelperBase<BaseClass>::exec()
stopTimer();
if (QWindowsNativeDialogBase *nd = nativeDialog()) {
nd->exec(m_ownerWindow);
- deleteNativeDialog();
+ m_nativeDialog.clear();
}
}
@@ -810,7 +815,7 @@ public:
inline void setDirectory(const QString &directory);
inline void updateDirectory() { setDirectory(m_data.directory().toLocalFile()); }
inline QString directory() const;
- virtual void exec(HWND owner = 0);
+ virtual void doExec(HWND owner = 0);
virtual void setNameFilters(const QStringList &f);
inline void selectNameFilter(const QString &filter);
inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); }
@@ -947,10 +952,12 @@ QString QWindowsNativeFileDialogBase::directory() const
return QString();
}
-void QWindowsNativeFileDialogBase::exec(HWND owner)
+void QWindowsNativeFileDialogBase::doExec(HWND owner)
{
if (QWindowsContext::verboseDialogs)
qDebug(">%s on %p", __FUNCTION__, (void *)owner);
+ // Show() blocks until the user closes the dialog, the dialog window
+ // gets a WM_CLOSE or the parent window is destroyed.
const HRESULT hr = m_fileDialog->Show(owner);
QWindowsDialogs::eatMouseMove();
if (QWindowsContext::verboseDialogs)
@@ -1611,7 +1618,7 @@ public:
static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data);
virtual void setWindowTitle(const QString &t) { m_title = t; }
- virtual void exec(HWND owner = 0);
+ virtual void doExec(HWND owner = 0);
virtual QPlatformDialogHelper::DialogCode result() const { return m_result; }
int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam);
@@ -1662,7 +1669,7 @@ QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options
setWindowTitle(m_options->windowTitle());
}
-void QWindowsXpNativeFileDialog::exec(HWND owner)
+void QWindowsXpNativeFileDialog::doExec(HWND owner)
{
int selectedFilterIndex = -1;
const QList<QUrl> selectedFiles =
@@ -1948,13 +1955,14 @@ public:
explicit QWindowsNativeColorDialog(const SharedPointerColor &color);
virtual void setWindowTitle(const QString &) {}
- virtual void exec(HWND owner = 0);
virtual QPlatformDialogHelper::DialogCode result() const { return m_code; }
public slots:
virtual void close() {}
private:
+ virtual void doExec(HWND owner = 0);
+
COLORREF m_customColors[CustomColorCount];
QPlatformDialogHelper::DialogCode m_code;
SharedPointerColor m_color;
@@ -1966,7 +1974,7 @@ QWindowsNativeColorDialog::QWindowsNativeColorDialog(const SharedPointerColor &c
std::fill(m_customColors, m_customColors + 16, COLORREF(0));
}
-void QWindowsNativeColorDialog::exec(HWND owner)
+void QWindowsNativeColorDialog::doExec(HWND owner)
{
typedef BOOL (WINAPI *ChooseColorWType)(LPCHOOSECOLORW);
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
index c0ee60cc1e..1501b02bd9 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
@@ -46,6 +46,7 @@
#include <qpa/qplatformdialoghelper.h>
#include <qpa/qplatformtheme.h>
#include <QtCore/QStringList>
+#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
@@ -64,8 +65,9 @@ namespace QWindowsDialogs
template <class BaseClass>
class QWindowsDialogHelperBase : public BaseClass
{
+ Q_DISABLE_COPY(QWindowsDialogHelperBase)
public:
- ~QWindowsDialogHelperBase() { deleteNativeDialog(); }
+ typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr;
virtual void exec();
virtual bool show(Qt::WindowFlags windowFlags,
@@ -79,7 +81,6 @@ protected:
QWindowsDialogHelperBase();
QWindowsNativeDialogBase *nativeDialog() const;
inline bool hasNativeDialog() const { return m_nativeDialog; }
- void deleteNativeDialog();
void timerEvent(QTimerEvent *);
private:
@@ -88,7 +89,7 @@ private:
inline void startDialogThread();
inline void stopTimer();
- QWindowsNativeDialogBase *m_nativeDialog;
+ QWindowsNativeDialogBasePtr m_nativeDialog;
HWND m_ownerWindow;
int m_timerId;
};