From 7196045b78b33cf135683d5c0b4e164f95231791 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 18 Nov 2010 12:42:14 +0100 Subject: Don't let posted events starve native dialogs (regression) After commit eb1015c7bbf135af3656110a4d112377c1209db8, it is possible for posted events to starve some of the (most likely internal) messages used by native dialogs. This commit reverts eb1015c7bbf135af3656110a4d112377c1209db8, and instead introduces a Windows timer to keep sendPostedEvents() happening while the event queue is very active. The GetMessage() hook we install will eventually see when the queue is empty and we can use PostMessage() again, which will then stop this timer. This fixes the regression reported in QTBUG-14655, as well as all of the other reported regressions and problems since the initial commit 31f1ff91028dd7f90925d5b3737e4d88b5fb07aa (which ensures that posted events are sent even when Windows is spinning the message loop). Task-number: QTBUG-14655 Reviewed-by: joao --- src/corelib/kernel/qeventdispatcher_win.cpp | 48 ++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index a719e72..3dccda6 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -84,7 +84,8 @@ extern uint qGlobalPostedEventsCount(); enum { WM_QT_SOCKETNOTIFIER = WM_USER, - WM_QT_SENDPOSTEDEVENTS = WM_USER + 1 + WM_QT_SENDPOSTEDEVENTS = WM_USER + 1, + SendPostedEventsWindowsTimerId = ~1u }; #if defined(Q_OS_WINCE) @@ -353,7 +354,7 @@ public: // for controlling when to send posted events QAtomicInt serialNumber; - int lastSerialNumber; + int lastSerialNumber, sendPostedEventsWindowsTimerId; QAtomicInt wakeUps; // timers @@ -378,7 +379,7 @@ public: QEventDispatcherWin32Private::QEventDispatcherWin32Private() : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0), getMessageHook(0), - serialNumber(0), lastSerialNumber(0), wakeUps(0) + serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), wakeUps(0) { resolveTimerAPI(); } @@ -485,17 +486,21 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA } } return 0; - } else if (message == WM_TIMER) { - Q_ASSERT(d != 0); - d->sendTimerEvent(wp); - return 0; - } else if (message == WM_QT_SENDPOSTEDEVENTS) { + } else if (message == WM_QT_SENDPOSTEDEVENTS + // we also use a Windows timer to send posted events when the message queue is full + || (message == WM_TIMER + && d->sendPostedEventsWindowsTimerId != 0 + && wp == d->sendPostedEventsWindowsTimerId)) { int localSerialNumber = d->serialNumber; if (localSerialNumber != d->lastSerialNumber) { d->lastSerialNumber = localSerialNumber; QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); } return 0; + } else if (message == WM_TIMER) { + Q_ASSERT(d != 0); + d->sendTimerEvent(wp); + return 0; } return DefWindowProc(hwnd, message, wp, lp); @@ -507,21 +512,36 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) QEventDispatcherWin32 *q = qobject_cast(QAbstractEventDispatcher::instance()); Q_ASSERT(q != 0); if (q) { + MSG *msg = (MSG *) lp; QEventDispatcherWin32Private *d = q->d_func(); int localSerialNumber = d->serialNumber; - MSG unused; - if ((HIWORD(GetQueueStatus(QS_INPUT | QS_RAWINPUT)) == 0 - && PeekMessage(&unused, 0, WM_TIMER, WM_TIMER, PM_NOREMOVE) == 0)) { - // no more input or timer events in the message queue or more than 10ms has elapsed since - // we send posted events, we can allow posted events to be sent now + if (HIWORD(GetQueueStatus(QS_TIMER | QS_INPUT | QS_RAWINPUT)) == 0) { + // no more input or timer events in the message queue, we can allow posted events to be sent normally now + if (d->sendPostedEventsWindowsTimerId != 0) { + // stop the timer to send posted events, since we now allow the WM_QT_SENDPOSTEDEVENTS message + KillTimer(d->internalHwnd, d->sendPostedEventsWindowsTimerId); + d->sendPostedEventsWindowsTimerId = 0; + } (void) d->wakeUps.fetchAndStoreRelease(0); - MSG *msg = (MSG *) lp; if (localSerialNumber != d->lastSerialNumber // if this message IS the one that triggers sendPostedEvents(), no need to post it again && (msg->hwnd != d->internalHwnd || msg->message != WM_QT_SENDPOSTEDEVENTS)) { PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0); } + } else if (d->sendPostedEventsWindowsTimerId == 0 + && localSerialNumber != d->lastSerialNumber + // if this message IS the one that triggers sendPostedEvents(), no need to post it again + && (msg->hwnd != d->internalHwnd + || msg->message != WM_QT_SENDPOSTEDEVENTS)) { + // start a special timer to continue delivering posted events while + // there are still input and timer messages in the message queue + d->sendPostedEventsWindowsTimerId = SetTimer(d->internalHwnd, + SendPostedEventsWindowsTimerId, + USER_TIMER_MINIMUM, + NULL); + // we don't check the return value of SetTimer()... if creating the timer failed, there's little + // we can do. we just have to accept that posted events will be starved } } } -- cgit v0.12 From ba4eafaa3bd46cfad891a4bbf1dd7dccefc4702e Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Fri, 19 Nov 2010 10:58:09 +0100 Subject: silence compiler warnings Silence shadowing warnings from gcc. --- src/sql/models/qsqlrelationaldelegate.h | 10 +++++----- src/testlib/qtesttouch.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sql/models/qsqlrelationaldelegate.h b/src/sql/models/qsqlrelationaldelegate.h index 7600e52..96760e1 100644 --- a/src/sql/models/qsqlrelationaldelegate.h +++ b/src/sql/models/qsqlrelationaldelegate.h @@ -59,23 +59,23 @@ class QSqlRelationalDelegate: public QItemDelegate { public: -explicit QSqlRelationalDelegate(QObject *parent = 0) - : QItemDelegate(parent) +explicit QSqlRelationalDelegate(QObject *aParent = 0) + : QItemDelegate(aParent) {} ~QSqlRelationalDelegate() {} -QWidget *createEditor(QWidget *parent, +QWidget *createEditor(QWidget *aParent, const QStyleOptionViewItem &option, const QModelIndex &index) const { const QSqlRelationalTableModel *sqlModel = qobject_cast(index.model()); QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0; if (!childModel) - return QItemDelegate::createEditor(parent, option, index); + return QItemDelegate::createEditor(aParent, option, index); - QComboBox *combo = new QComboBox(parent); + QComboBox *combo = new QComboBox(aParent); combo->setModel(childModel); combo->setModelColumn(childModel->fieldIndex(sqlModel->relation(index.column()).displayColumn())); combo->installEventFilter(const_cast(this)); diff --git a/src/testlib/qtesttouch.h b/src/testlib/qtesttouch.h index 1beef85..6c58e4c 100644 --- a/src/testlib/qtesttouch.h +++ b/src/testlib/qtesttouch.h @@ -106,8 +106,8 @@ namespace QTest } private: - QTouchEventSequence(QWidget *widget, QTouchEvent::DeviceType deviceType) - : targetWidget(widget), deviceType(deviceType) + QTouchEventSequence(QWidget *widget, QTouchEvent::DeviceType aDeviceType) + : targetWidget(widget), deviceType(aDeviceType) { } QTouchEventSequence(const QTouchEventSequence &v); -- cgit v0.12 From 4e9b721af573e7d1a16b35778059b374520cf055 Mon Sep 17 00:00:00 2001 From: Sam Magnuson Date: Fri, 19 Nov 2010 11:24:58 +0100 Subject: Compile with QT_NO_PROXYSCREEN. Merge-request: 931 Reviewed-by: Oswald Buddenhagen --- src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index 2eeee24..fbc539b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -344,9 +344,11 @@ void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, if (!win) return; +#ifndef QT_NO_QWS_PROXYSCREEN QWExtra *extra = qt_widget_private(widget)->extraData(); if (extra && extra->proxyWidget) return; +#endif const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff); const QRect windowGeometry = geometry(); -- cgit v0.12 From eaa0529642c90de3ebc07d819c0c0e8ed96a79be Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 19 Nov 2010 13:29:04 +0100 Subject: Fix compilation with Sun Studio 12.1. Error was: "tst_qdbusconnection.cpp", line 301: Error: Could not find a match for QTest::qCompare(QObject*, MyObject*, const char[29], const char[5], const char[24], int) needed in tst_QDBusConnection::registerObject(). "tst_qdbusconnection.cpp", line 498: Error: Could not find a match for QTest::qCompare(QObject*, TestObject*, const char[39], const char[12], const char[24], int) needed in tst_QDBusConnection::callSelf(). Task-number: QTBUG-15324 Patch-by: Pavel Heimlich Reviewed-by: Thiago Macieira --- tests/auto/qdbusconnection/tst_qdbusconnection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/qdbusconnection/tst_qdbusconnection.cpp index 96209b1..599abbd 100644 --- a/tests/auto/qdbusconnection/tst_qdbusconnection.cpp +++ b/tests/auto/qdbusconnection/tst_qdbusconnection.cpp @@ -298,7 +298,7 @@ void tst_QDBusConnection::registerObject() // register one object at root: MyObject obj; QVERIFY(con.registerObject(path, &obj, QDBusConnection::ExportAllSlots)); - QCOMPARE(con.objectRegisteredAt(path), &obj); + QCOMPARE(con.objectRegisteredAt(path), static_cast(&obj)); QVERIFY(callMethod(con, path)); QCOMPARE(obj.path, path); } @@ -495,7 +495,7 @@ void tst_QDBusConnection::callSelf() QDBusConnection connection = QDBusConnection::sessionBus(); QVERIFY(connection.registerObject("/test", &testObject, QDBusConnection::ExportAllContents)); - QCOMPARE(connection.objectRegisteredAt("/test"), &testObject); + QCOMPARE(connection.objectRegisteredAt("/test"), static_cast(&testObject)); QVERIFY(connection.registerService(serviceName())); QDBusInterface interface(serviceName(), "/test"); QVERIFY(interface.isValid()); -- cgit v0.12