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>
This commit is contained in:
parent
da5d9e664f
commit
b7ca6a81db
@ -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();
|
||||
|
||||
|
@ -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, ¬ifierEvent);
|
||||
}
|
||||
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user