direct2d: Use simple event posting to avoid event queue lock up
In rare cases, the Windows event loop can be spinning inside the inner loop and the message hook is never called. This can be triggered on the Direct2D platform by opening 32+ window handles. The issue can be worked around by using the same approach Windows CE uses: don't rely on the message hook to inform the event loop that the post message has been delivered. Instead, uninstall the hook and let it be called directly by the event loop. Task-number: QTBUG-42428 Change-Id: I10280126dd50729bc260aa5f7029549e2e061c01 Reviewed-by: Louai Al-Khanji <louai.al-khanji@theqtcompany.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
This commit is contained in:
parent
21e5d77e85
commit
3d70925ee5
@ -434,9 +434,10 @@ static inline UINT inputTimerMask()
|
||||
|
||||
LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
|
||||
{
|
||||
QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
|
||||
Q_ASSERT(q != 0);
|
||||
|
||||
if (wp == PM_REMOVE) {
|
||||
QEventDispatcherWin32 *q = qobject_cast<QEventDispatcherWin32 *>(QAbstractEventDispatcher::instance());
|
||||
Q_ASSERT(q != 0);
|
||||
if (q) {
|
||||
MSG *msg = (MSG *) lp;
|
||||
QEventDispatcherWin32Private *d = q->d_func();
|
||||
@ -472,7 +473,7 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
|
||||
#ifdef Q_OS_WINCE
|
||||
return 0;
|
||||
#else
|
||||
return CallNextHookEx(0, code, wp, lp);
|
||||
return q->d_func()->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -643,15 +644,7 @@ void QEventDispatcherWin32::createInternalHwnd()
|
||||
return;
|
||||
d->internalHwnd = qt_create_internal_window(this);
|
||||
|
||||
#ifndef Q_OS_WINCE
|
||||
// setup GetMessage hook needed to drive our posted events
|
||||
d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
|
||||
if (!d->getMessageHook) {
|
||||
int errorCode = GetLastError();
|
||||
qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s",
|
||||
errorCode, qPrintable(qt_error_string(errorCode)));
|
||||
}
|
||||
#endif
|
||||
installMessageHook();
|
||||
|
||||
// register all socket notifiers
|
||||
QList<int> sockets = (d->sn_read.keys().toSet()
|
||||
@ -665,6 +658,35 @@ void QEventDispatcherWin32::createInternalHwnd()
|
||||
d->registerTimer(d->timerVec.at(i));
|
||||
}
|
||||
|
||||
void QEventDispatcherWin32::installMessageHook()
|
||||
{
|
||||
Q_D(QEventDispatcherWin32);
|
||||
|
||||
if (d->getMessageHook)
|
||||
return;
|
||||
|
||||
#ifndef Q_OS_WINCE
|
||||
// setup GetMessage hook needed to drive our posted events
|
||||
d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
|
||||
if (!d->getMessageHook) {
|
||||
int errorCode = GetLastError();
|
||||
qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s",
|
||||
errorCode, qPrintable(qt_error_string(errorCode)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void QEventDispatcherWin32::uninstallMessageHook()
|
||||
{
|
||||
Q_D(QEventDispatcherWin32);
|
||||
|
||||
#ifndef Q_OS_WINCE
|
||||
if (d->getMessageHook)
|
||||
UnhookWindowsHookEx(d->getMessageHook);
|
||||
#endif
|
||||
d->getMessageHook = 0;
|
||||
}
|
||||
|
||||
QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
|
||||
: QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent)
|
||||
{
|
||||
@ -750,10 +772,9 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
||||
}
|
||||
}
|
||||
if (haveMessage) {
|
||||
#ifdef Q_OS_WINCE
|
||||
// WinCE doesn't support hooks at all, so we have to call this by hand :(
|
||||
(void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg);
|
||||
#endif
|
||||
if (!d->getMessageHook)
|
||||
(void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg);
|
||||
|
||||
if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
|
||||
if (seenWM_QT_SENDPOSTEDEVENTS) {
|
||||
@ -1134,11 +1155,7 @@ void QEventDispatcherWin32::closingDown()
|
||||
d->timerVec.clear();
|
||||
d->timerDict.clear();
|
||||
|
||||
#ifndef Q_OS_WINCE
|
||||
if (d->getMessageHook)
|
||||
UnhookWindowsHookEx(d->getMessageHook);
|
||||
d->getMessageHook = 0;
|
||||
#endif
|
||||
uninstallMessageHook();
|
||||
}
|
||||
|
||||
bool QEventDispatcherWin32::event(QEvent *e)
|
||||
|
@ -67,6 +67,8 @@ class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcher
|
||||
|
||||
protected:
|
||||
void createInternalHwnd();
|
||||
void installMessageHook();
|
||||
void uninstallMessageHook();
|
||||
|
||||
public:
|
||||
explicit QEventDispatcherWin32(QObject *parent = 0);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "qwindowsdirect2dwindow.h"
|
||||
|
||||
#include "qwindowscontext.h"
|
||||
#include "qwindowsguieventdispatcher.h"
|
||||
|
||||
#include <qplatformdefs.h>
|
||||
#include <QtCore/QCoreApplication>
|
||||
@ -47,6 +48,16 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QWindowsDirect2DEventDispatcher : public QWindowsGuiEventDispatcher
|
||||
{
|
||||
public:
|
||||
QWindowsDirect2DEventDispatcher(QObject *parent = 0)
|
||||
: QWindowsGuiEventDispatcher(parent)
|
||||
{
|
||||
uninstallMessageHook(); // ### Workaround for QTBUG-42428
|
||||
}
|
||||
};
|
||||
|
||||
class QWindowsDirect2DIntegrationPrivate
|
||||
{
|
||||
public:
|
||||
@ -237,6 +248,11 @@ QPlatformBackingStore *QWindowsDirect2DIntegration::createPlatformBackingStore(Q
|
||||
return new QWindowsDirect2DBackingStore(window);
|
||||
}
|
||||
|
||||
QAbstractEventDispatcher *QWindowsDirect2DIntegration::createEventDispatcher() const
|
||||
{
|
||||
return new QWindowsDirect2DEventDispatcher;
|
||||
}
|
||||
|
||||
QWindowsDirect2DContext *QWindowsDirect2DIntegration::direct2DContext() const
|
||||
{
|
||||
return &d->m_d2dContext;
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE;
|
||||
QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE;
|
||||
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE;
|
||||
QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
|
||||
|
||||
QWindowsDirect2DContext *direct2DContext() const;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user