Cocoa: Don't stop NSApp when showing a modal dialog
We manage embedded modal sessions with a stack and only run the top-most session. We also stop the last modal session before starting a new one. However, if there is no modal session running yet, we end up stopping NSApp. This seems to cause ill side effects on OS X 10.9. Notably, starting a new modal session outside QCocoaEventDispatcher, like when opening a native file dialog, makes this last modal session impossible for the user to quit. In this patch, we make sure NSApp is kept running if there's no modal session running yet, akin to calling QDialog::exec() at the event dispatcher level. The behavior for ensuing modal sessions remains unchanged. Task-number: QTBUG-34677 Change-Id: I6a23b191e4dce18514504b8e953f8caa7fad8731 Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
This commit is contained in:
parent
9a9feab102
commit
ff3dcc49c4
@ -163,6 +163,7 @@ public:
|
|||||||
// The following variables help organizing modal sessions:
|
// The following variables help organizing modal sessions:
|
||||||
QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
|
QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
|
||||||
bool currentExecIsNSAppRun;
|
bool currentExecIsNSAppRun;
|
||||||
|
bool modalSessionOnNSAppRun;
|
||||||
bool nsAppRunCalledByQt;
|
bool nsAppRunCalledByQt;
|
||||||
bool cleanupModalSessionsNeeded;
|
bool cleanupModalSessionsNeeded;
|
||||||
uint processEventsCalled;
|
uint processEventsCalled;
|
||||||
|
@ -721,7 +721,6 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
|
|||||||
// setting currentModalSessionCached to zero, so that interrupt() calls
|
// setting currentModalSessionCached to zero, so that interrupt() calls
|
||||||
// [NSApp abortModal] if another modal session is currently running
|
// [NSApp abortModal] if another modal session is currently running
|
||||||
Q_Q(QCocoaEventDispatcher);
|
Q_Q(QCocoaEventDispatcher);
|
||||||
q->interrupt();
|
|
||||||
|
|
||||||
// Add a new, empty (null), NSModalSession to the stack.
|
// Add a new, empty (null), NSModalSession to the stack.
|
||||||
// It will become active the next time QEventDispatcher::processEvents is called.
|
// It will become active the next time QEventDispatcher::processEvents is called.
|
||||||
@ -734,6 +733,12 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
|
|||||||
cocoaModalSessionStack.push(info);
|
cocoaModalSessionStack.push(info);
|
||||||
updateChildrenWorksWhenModal();
|
updateChildrenWorksWhenModal();
|
||||||
currentModalSessionCached = 0;
|
currentModalSessionCached = 0;
|
||||||
|
if (currentExecIsNSAppRun) {
|
||||||
|
modalSessionOnNSAppRun = true;
|
||||||
|
q->wakeUp();
|
||||||
|
} else {
|
||||||
|
q->interrupt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
|
void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
|
||||||
@ -772,6 +777,7 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
|
|||||||
runLoopTimerRef(0),
|
runLoopTimerRef(0),
|
||||||
blockSendPostedEvents(false),
|
blockSendPostedEvents(false),
|
||||||
currentExecIsNSAppRun(false),
|
currentExecIsNSAppRun(false),
|
||||||
|
modalSessionOnNSAppRun(false),
|
||||||
nsAppRunCalledByQt(false),
|
nsAppRunCalledByQt(false),
|
||||||
cleanupModalSessionsNeeded(false),
|
cleanupModalSessionsNeeded(false),
|
||||||
processEventsCalled(0),
|
processEventsCalled(0),
|
||||||
@ -902,6 +908,14 @@ void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info)
|
|||||||
// processEvents() was called "manually," ignore this source for now
|
// processEvents() was called "manually," ignore this source for now
|
||||||
d->maybeCancelWaitForMoreEvents();
|
d->maybeCancelWaitForMoreEvents();
|
||||||
return;
|
return;
|
||||||
|
} else if (d->modalSessionOnNSAppRun) {
|
||||||
|
// We're about to spawn the 1st modal session on top of the main runloop.
|
||||||
|
// Instead of calling processPostedEvents(), which would need us stop
|
||||||
|
// NSApp, we just re-enter processEvents(). This is equivalent to calling
|
||||||
|
// QDialog::exec() except that it's done in a non-blocking way.
|
||||||
|
d->modalSessionOnNSAppRun = false;
|
||||||
|
d->q_func()->processEvents(QEventLoop::DialogExec | QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
d->processPostedEvents();
|
d->processPostedEvents();
|
||||||
d->maybeCancelWaitForMoreEvents();
|
d->maybeCancelWaitForMoreEvents();
|
||||||
|
Loading…
Reference in New Issue
Block a user