Fix crash when handling WM_PAINT during COM operations
authorMiikka Heikkinen <miikka.heikkinen@digia.com>
Tue, 23 Oct 2012 13:25:47 +0000 (16:25 +0300)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Thu, 25 Oct 2012 12:10:04 +0000 (14:10 +0200)
Synchronous expose corrupts painter state if it is done during existing
paint operation, which can happen e.g. when requesting some value from
dumpcpp generated wrapper inside a slot.

Fixed by implementing support for setting asynchronous expose and
doing expose according to the setting in handleWmPaint().

Task-number: QTBUG-27209
Change-Id: I89b5aa823fda947d26b1a4757f129e7c31ea408b
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
src/plugins/platforms/windows/qwindowscontext.cpp
src/plugins/platforms/windows/qwindowscontext.h
src/plugins/platforms/windows/qwindowsintegration.cpp
src/plugins/platforms/windows/qwindowswindow.cpp

index 42db58a..a074938 100644 (file)
@@ -259,6 +259,7 @@ struct QWindowsContextPrivate {
     const HRESULT m_oleInitializeResult;
     const QByteArray m_eventType;
     QWindow *m_lastActiveWindow;
+    bool m_asyncExpose;
 };
 
 QWindowsContextPrivate::QWindowsContextPrivate() :
@@ -267,7 +268,7 @@ QWindowsContextPrivate::QWindowsContextPrivate() :
     m_defaultDPI(GetDeviceCaps(m_displayContext,LOGPIXELSY)),
     m_oleInitializeResult(OleInitialize(NULL)),
     m_eventType(QByteArrayLiteral("windows_generic_MSG")),
-    m_lastActiveWindow(0)
+    m_lastActiveWindow(0), m_asyncExpose(0)
 {
 #ifndef Q_OS_WINCE
     QWindowsContext::user32dll.init();
@@ -923,6 +924,16 @@ void QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
 }
 #endif
 
+bool QWindowsContext::asyncExpose() const
+{
+    return d->m_asyncExpose;
+}
+
+void QWindowsContext::setAsyncExpose(bool value)
+{
+    d->m_asyncExpose = value;
+}
+
 /*!
     \brief Windows functions for actual windows.
 
index ef48a52..21a846e 100644 (file)
@@ -184,6 +184,8 @@ public:
 #endif
 
     static QByteArray comErrorString(HRESULT hr);
+    bool asyncExpose() const;
+    void setAsyncExpose(bool value);
 
 private:
     void handleFocusEvent(QtWindows::WindowsEventType et, QWindowsWindow *w);
index f95fbf4..b7309c3 100644 (file)
@@ -96,6 +96,7 @@ QT_BEGIN_NAMESPACE
 class QWindowsNativeInterface : public QPlatformNativeInterface
 {
     Q_OBJECT
+    Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose)
 public:
 #ifndef QT_NO_OPENGL
     virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context);
@@ -106,6 +107,8 @@ public:
     Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate,
                                           const QString &windowName,
                                           void *eventProc) const;
+    bool asyncExpose() const;
+    void setAsyncExpose(bool value);
 };
 
 void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
@@ -183,6 +186,16 @@ void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTempl
     return hwnd;
 }
 
+bool QWindowsNativeInterface::asyncExpose() const
+{
+    return QWindowsContext::instance()->asyncExpose();
+}
+
+void QWindowsNativeInterface::setAsyncExpose(bool value)
+{
+    QWindowsContext::instance()->setAsyncExpose(value);
+}
+
 /*!
     \class QWindowsIntegration
     \brief QPlatformIntegration implementation for Windows.
index 99b8922..9aada91 100644 (file)
@@ -1158,7 +1158,8 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
             InvalidateRect(hwnd, 0, false);
         BeginPaint(hwnd, &ps);
         QWindowSystemInterface::handleExposeEvent(window(), QRegion(qrectFromRECT(ps.rcPaint)));
-        QWindowSystemInterface::flushWindowSystemEvents();
+        if (!QWindowsContext::instance()->asyncExpose())
+            QWindowSystemInterface::flushWindowSystemEvents();
 
         EndPaint(hwnd, &ps);
     } else {
@@ -1169,7 +1170,8 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
             qDebug() << __FUNCTION__ << this << window() << updateRect;
 
         QWindowSystemInterface::handleExposeEvent(window(), QRegion(updateRect));
-        QWindowSystemInterface::flushWindowSystemEvents();
+        if (!QWindowsContext::instance()->asyncExpose())
+            QWindowSystemInterface::flushWindowSystemEvents();
         EndPaint(hwnd, &ps);
     }
     return true;