From 8f74a64f3f2f5a6273c5e7de1591585a97dff82d Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Fri, 18 Feb 2011 09:20:06 +0100 Subject: 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. --- src/gui/kernel/qeventdispatcher_mac.mm | 60 ++++++++++++++++++++++++---------- 1 file 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(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); -- cgit v0.12