summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBradley T. Hughes <bradley.hughes@nokia.com>2012-01-23 08:59:27 +0100
committerQt by Nokia <qt-info@nokia.com>2012-02-03 01:40:24 +0100
commitb7ca6a81dbf6a2b96c8f04b856372050618e60c0 (patch)
tree58ae6adda02901ef8d035fc96734044a1f64fbcd
parentda5d9e664f27abe41748f4360624c235c20e8c15 (diff)
processEvents(WaitForMoreEvents) should return after delivering events
The Cocoa event dispatcher sends timer, socket, and posted events correctly, but they are not NSEvents, and as such, they do not cause [NSApp nextEventMatchingMask] to return. When calling processEvents() with WaitForMoreEvents, but the EventLoopExec flag isn't set, we want to interrupt the WaitForMoreEvents. As a result, We should not call wakeUp() at the top of processEvents(), otherwise we end up shortcutting other event sources. We also do not need to call QCoreApplication::sendPostedEvents() directly either in processEvents(), it's the postedEventsSource job to do that. The interruptLater mechanism is always run when calling processEvents() directly (not via exec()), which causes problems when testing processEvents(). Don't use interruptLater unless the modal sessions change (which is indicated by the cached session pointer being reset to zero). Change-Id: Iec2b49a4f306b2702c979522f12a28d0b5fbd0b4 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@nokia.com>
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm36
2 files changed, 28 insertions, 11 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index e842468c7b..a4a1286fab 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -149,6 +149,8 @@ class QCocoaEventDispatcherPrivate : public QAbstractEventDispatcherPrivate
public:
QCocoaEventDispatcherPrivate();
+ uint processEventsFlags;
+
// timer handling
QTimerInfoList timerInfoList;
CFRunLoopTimerRef runLoopTimerRef;
@@ -173,6 +175,7 @@ public:
void beginModalSession(QWindow *widget);
void endModalSession(QWindow *widget);
void cancelWaitForMoreEvents();
+ void maybeCancelWaitForMoreEvents();
void cleanupModalSessions();
void ensureNSAppInitialized();
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index dbb8625aeb..6de22cf58c 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -114,6 +114,7 @@ void QCocoaEventDispatcherPrivate::activateTimer(CFRunLoopTimerRef, void *info)
QCocoaEventDispatcherPrivate *d = static_cast<QCocoaEventDispatcherPrivate *>(info);
(void) d->timerInfoList.activateTimers();
d->maybeStartCFRunLoopTimer();
+ d->maybeCancelWaitForMoreEvents();
}
void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
@@ -275,6 +276,8 @@ void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CF
if (socketInfo->writeNotifier)
QGuiApplication::sendEvent(socketInfo->writeNotifier, &notifierEvent);
}
+
+ eventDispatcher->maybeCancelWaitForMoreEvents();
}
/*
@@ -508,13 +511,12 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
bool interruptLater = false;
QtCocoaInterruptDispatcher::cancelInterruptLater();
- // In case we end up recursing while we now process events, make sure
- // that we send remaining posted Qt events before this call returns:
- wakeUp();
emit awake();
bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents;
bool retVal = false;
+ uint oldflags = d->processEventsFlags;
+ d->processEventsFlags = flags;
forever {
if (d->interrupt)
break;
@@ -567,6 +569,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
}
retVal = true;
} else {
+ bool hadModalSession = d->currentModalSessionCached != 0;
// We cannot block the thread (and run in a tight loop).
// Instead we will process all current pending events and return.
d->ensureNSAppInitialized();
@@ -628,17 +631,13 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
}
} while (!d->interrupt && event != nil);
- // Be sure to flush the Qt posted events when not using exec mode
- // (exec mode will always do this call from the event loop source):
- if (!d->interrupt)
- QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
-
// Since the window that holds modality might have changed while processing
// events, we we need to interrupt when we return back the previous process
// event recursion to ensure that we spin the correct modal session.
// We do the interruptLater at the end of the function to ensure that we don't
// disturb the 'wait for more events' below (as deleteLater will post an event):
- interruptLater = true;
+ if (hadModalSession && d->currentModalSessionCached == 0)
+ interruptLater = true;
}
bool canWait = (d->threadData->canWait
&& !retVal
@@ -656,6 +655,8 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
}
}
+ d->processEventsFlags = oldflags;
+
// If we're interrupted, we need to interrupt the _current_
// recursion as well to check if it is still supposed to be
// executing. This way we wind down the stack until we land
@@ -878,7 +879,8 @@ void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
}
QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
- : runLoopTimerRef(0),
+ : processEventsFlags(0),
+ runLoopTimerRef(0),
blockSendPostedEvents(false),
currentExecIsNSAppRun(false),
nsAppRunCalledByQt(false),
@@ -1007,7 +1009,9 @@ void QCocoaEventDispatcherPrivate::firstLoopEntry(CFRunLoopObserverRef ref,
void QCocoaEventDispatcherPrivate::postedEventsSourcePerformCallback(void *info)
{
- static_cast<QCocoaEventDispatcherPrivate *>(info)->processPostedEvents();
+ QCocoaEventDispatcherPrivate *d = static_cast<QCocoaEventDispatcherPrivate *>(info);
+ d->processPostedEvents();
+ d->maybeCancelWaitForMoreEvents();
}
void QCocoaEventDispatcherPrivate::cancelWaitForMoreEvents()
@@ -1020,6 +1024,16 @@ void QCocoaEventDispatcherPrivate::cancelWaitForMoreEvents()
subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO];
}
+void QCocoaEventDispatcherPrivate::maybeCancelWaitForMoreEvents()
+{
+ if ((processEventsFlags & (QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents)) == QEventLoop::WaitForMoreEvents) {
+ // RunLoop sources are not NSEvents, but they do generate Qt events. If
+ // WaitForMoreEvents was set, but EventLoopExec is not, processEvents()
+ // should return after a source has sent some Qt events.
+ cancelWaitForMoreEvents();
+ }
+}
+
void QCocoaEventDispatcher::interrupt()
{
Q_D(QCocoaEventDispatcher);