From b0016ea9a6b225757e3ee06b50e8f7d05463ddf7 Mon Sep 17 00:00:00 2001 From: Benjamin Poulain Date: Mon, 21 Sep 2009 11:58:21 +0200 Subject: On Mac, the posted events are processed on the first time in the loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Mac OS X, we use a custom source for posted events. The first time the event loop is entered, the custom source is added to the native event dispatcher but the events are not processed. In Qt, we expect those events to be processed. To work around the problem, a new observer is added to the event loop. This observer is only triggered the first time the event loop is entered. When the observer is triggered, the posted events are sent. Task-number: QTBUG-4521 Reviewed-by: Richard Moe Gustavsen Reviewed-by: João Abecasis --- src/gui/kernel/qeventdispatcher_mac.mm | 33 +++++++++++++++- src/gui/kernel/qeventdispatcher_mac_p.h | 1 + .../auto/qcoreapplication/tst_qcoreapplication.cpp | 45 +++++++++++++++------- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm index f05d56f..7a3af86 100644 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ b/src/gui/kernel/qeventdispatcher_mac.mm @@ -909,6 +909,22 @@ QEventDispatcherMac::QEventDispatcherMac(QObject *parent) QEventDispatcherMacPrivate::waitingObserverCallback, &observerContext); CFRunLoopAddObserver(mainRunLoop(), d->waitingObserver, kCFRunLoopCommonModes); + + /* The first cycle in the loop adds the source and the events of the source + are not processed. + We use an observer to process the posted events for the first + execution of the loop. */ + CFRunLoopObserverContext firstTimeObserverContext; + bzero(&firstTimeObserverContext, sizeof(CFRunLoopObserverContext)); + firstTimeObserverContext.info = d; + CFRunLoopObserverRef firstTimeObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, + kCFRunLoopEntry, + /* repeats = */ false, + 0, + QEventDispatcherMacPrivate::firstLoopEntry, + &firstTimeObserverContext); + CFRunLoopAddObserver(mainRunLoop(), firstTimeObserver, kCFRunLoopCommonModes); + CFRelease(firstTimeObserver); } void QEventDispatcherMacPrivate::waitingObserverCallback(CFRunLoopObserverRef, @@ -925,9 +941,8 @@ Boolean QEventDispatcherMacPrivate::postedEventSourceEqualCallback(const void *i return info1 == info2; } -void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info) +inline static void processPostedEvents(QEventDispatcherMacPrivate *const d, const bool blockSendPostedEvents) { - QEventDispatcherMacPrivate *d = static_cast(info); if (blockSendPostedEvents) { CFRunLoopSourceSignal(d->postedEventsSource); } else { @@ -938,6 +953,20 @@ void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info) } } +void QEventDispatcherMacPrivate::firstLoopEntry(CFRunLoopObserverRef ref, + CFRunLoopActivity activity, + void *info) +{ + Q_UNUSED(ref); + Q_UNUSED(activity); + processPostedEvents(static_cast(info), blockSendPostedEvents); +} + +void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info) +{ + processPostedEvents(static_cast(info), blockSendPostedEvents); +} + void QEventDispatcherMac::interrupt() { Q_D(QEventDispatcherMac); diff --git a/src/gui/kernel/qeventdispatcher_mac_p.h b/src/gui/kernel/qeventdispatcher_mac_p.h index e94d98a..15bc6f8 100644 --- a/src/gui/kernel/qeventdispatcher_mac_p.h +++ b/src/gui/kernel/qeventdispatcher_mac_p.h @@ -196,6 +196,7 @@ private: static void activateTimer(CFRunLoopTimerRef, void *info); static void waitingObserverCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); + static void firstLoopEntry(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info); }; #ifdef QT_MAC_USE_COCOA diff --git a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp index 9ddd54a..4b38044 100644 --- a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp +++ b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp @@ -47,6 +47,7 @@ class tst_QCoreApplication: public QObject { Q_OBJECT private slots: + void sendEventsOnProcessEvents(); // this must be the first test void getSetCheck(); void qAppName(); void argc(); @@ -59,6 +60,35 @@ private slots: void globalPostedEventsCount(); }; +class EventSpy : public QObject +{ + Q_OBJECT + +public: + QList recordedEvents; + bool eventFilter(QObject *, QEvent *event) + { + recordedEvents.append(event->type()); + return false; + } +}; + +void tst_QCoreApplication::sendEventsOnProcessEvents() +{ + int argc = 1; + char *argv[] = { "tst_qcoreapplication" }; + QCoreApplication app(argc, argv); + + EventSpy spy; + app.installEventFilter(&spy); + + QCoreApplication::postEvent(&app, new QEvent(QEvent::Type(QEvent::User + 1))); + QCoreApplication::processEvents(); + QList expected; + expected << QEvent::User + 1; + QCOMPARE(expected, spy.recordedEvents); +} + void tst_QCoreApplication::getSetCheck() { // do not crash @@ -114,19 +144,6 @@ void tst_QCoreApplication::argc() } } -class EventSpy : public QObject -{ - Q_OBJECT - -public: - QList recordedEvents; - bool eventFilter(QObject *, QEvent *event) - { - recordedEvents.append(event->type()); - return false; - } -}; - class EventGenerator : public QObject { Q_OBJECT @@ -394,6 +411,8 @@ public: } case QEvent::User + 1: break; + default: + break; } return QObject::event(event); } -- cgit v0.12