diff options
author | Richard Moe Gustavsen <richard.gustavsen@nokia.com> | 2011-02-18 08:20:06 (GMT) |
---|---|---|
committer | Richard Moe Gustavsen <richard.gustavsen@nokia.com> | 2011-02-18 08:20:06 (GMT) |
commit | 8f74a64f3f2f5a6273c5e7de1591585a97dff82d (patch) | |
tree | 1163a8ecb656274389aeecd46777ccdbd52aad5d /src/gui | |
parent | 5727255ce985862ac9970f3fb2db96735700b92f (diff) | |
download | Qt-8f74a64f3f2f5a6273c5e7de1591585a97dff82d.zip Qt-8f74a64f3f2f5a6273c5e7de1591585a97dff82d.tar.gz Qt-8f74a64f3f2f5a6273c5e7de1591585a97dff82d.tar.bz2 |
Cocoa: implement eventdispatcher flag excludeUserInputEvents
When executing modal windows, the event dispatcher would not respect
the QEventLoop::ExcludeUserInputEvents. This patch implements
this support. The way it now works is that we fetch events manually
from NSApplication and do the dispatching ourselves in those cases.
From earlier research, this patch has shown to be a bit unreliable
in some cases, and might have some sideeffects. Hence the reason
we avoid it if we can. But it still feels better that we try to
follow the flag in those few application that wants to do this.
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/kernel/qeventdispatcher_mac.mm | 60 |
1 files changed, 42 insertions, 18 deletions
diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm index b4f3805..677a736 100644 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ b/src/gui/kernel/qeventdispatcher_mac.mm @@ -561,6 +561,7 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) wakeUp(); emit awake(); + bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents; bool retVal = false; forever { if (d->interrupt) @@ -571,7 +572,7 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) NSEvent* event = 0; // First, send all previously excluded input events, if any: - if (!(flags & QEventLoop::ExcludeUserInputEvents)) { + if (!excludeUserEvents) { while (!d->queuedUserInputEvents.isEmpty()) { event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); if (!filterEvent(event)) { @@ -590,9 +591,8 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) // Finally, if we are to exclude user input events, we cannot call [NSApp run] // as we then loose control over which events gets dispatched: const bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning]; - const bool canExec_Qt = - (flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec) - && !(flags & QEventLoop::ExcludeUserInputEvents); + const bool canExec_Qt = !excludeUserEvents && + (flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec) ; if (canExec_Qt && canExec_3rdParty) { // We can use exec-mode, meaning that we can stay in a tight loop until @@ -620,22 +620,46 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) // Instead we will process all current pending events and return. d->ensureNSAppInitialized(); if (NSModalSession session = d->currentModalSession()) { - if (flags & QEventLoop::WaitForMoreEvents) - qt_mac_waitForMoreModalSessionEvents(); - NSInteger status = [NSApp runModalSession:session]; - if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) { - // INVARIANT: Someone called [NSApp stopModal:] from outside the event - // dispatcher (e.g to stop a native dialog). But that call wrongly stopped - // 'session' as well. As a result, we need to restart all internal sessions: - d->temporarilyStopAllModalSessions(); - } - retVal = true; - } else do { - event = [NSApp nextEventMatchingMask:NSAnyEventMask + // INVARIANT: a modal window is executing. + if (!excludeUserEvents) { + // Since we can dispatch all kinds of events, we choose + // to use cocoa's native way of running modal sessions: + if (flags & QEventLoop::WaitForMoreEvents) + qt_mac_waitForMoreModalSessionEvents(); + NSInteger status = [NSApp runModalSession:session]; + if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) { + // INVARIANT: Someone called [NSApp stopModal:] from outside the event + // dispatcher (e.g to stop a native dialog). But that call wrongly stopped + // 'session' as well. As a result, we need to restart all internal sessions: + d->temporarilyStopAllModalSessions(); + } + retVal = true; + } else do { + // Dispatch all non-user events (but que non-user events up for later). In + // this case, we need more control over which events gets dispatched, and + // cannot use [NSApp runModalSession:session]: + event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil - inMode:NSDefaultRunLoopMode + inMode:NSModalPanelRunLoopMode dequeue: YES]; + if (event) { + if (IsMouseOrKeyEvent(event)) { + [event retain]; + d->queuedUserInputEvents.append(event); + continue; + } + if (!filterEvent(event) && qt_mac_send_event(flags, event, 0)) + retVal = true; + } + } while (!d->interrupt && event != nil); + } else do { + // INVARIANT: No modal window is executing. + event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue: YES]; + if (event) { if (flags & QEventLoop::ExcludeUserInputEvents) { if (IsMouseOrKeyEvent(event)) { @@ -649,7 +673,7 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) } } while (!d->interrupt && event != nil); - // Be sure to flush the Qt posted events when not using mode + // 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); |