summaryrefslogtreecommitdiff
path: root/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
diff options
context:
space:
mode:
authorGabriel de Dietrich <gabriel.dedietrich@digia.com>2013-06-19 12:27:51 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-08-29 12:44:07 +0200
commit1e14762b8d79118540bd09a84dd3e48f4f5e113e (patch)
treef06cb1b7ccb161f3495d2c1abb941c2911a50314 /src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
parentee9b9d9fd9a714f97ed8f7e26404c2f113588e9c (diff)
downloadqtbase-1e14762b8d79118540bd09a84dd3e48f4f5e113e.tar.gz
Make QGuiApplication::exec() run within NSApplicationMain()
We follow the same pattern as for iOS and Windows ports, making sure the user's main() runs in a platform friendly environment. In this particular case, it means calling the user's main() during the call of NSApplicationMain(), and calling the user's main() function (renamed to qMain() as in Windows) after receiving NSApplicationDidFinishLaunchingNotification. In practice, this means that NSApp is running when qMain() is called, and therefore when QCoreApplication::exec() is called. For those command-line utilities running on QGuiApplication, or any deriving class, and that do not provide a bundle, we override the main bundle's dictionary and get NSApplicationMain() to run as usual. Added cocoa/cocoamain "subdir" to build libqtcocoamain.a (together with cocoa/cocoaplugin -- plugins/platforms/cocoa is made a subdirs project). This library is linked against all GUI Qt apps and provides the actual main() function. It also catches the launching NSApplication notifications, and calls the user's qMain() function. Note that this will happen in the same cases when the user's application will run with the Cocoa QPA plugin. Launch related code in QCocoaApplicationDelegate is moved to libqtcocoamain, QNSApplication is removed (but sendEvent: redirection still there), and code in QCocoaEventDispatcher dealing with calling [NSApp run] and related has been removed since it's become unreachable. ChangeLog: [Qt for Mac] Make QGuiApplication::exec() run within NSApplicationMain() Change-Id: I790e5138c29aac2e0215a9147d0148fece40ca22 Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm')
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm107
1 files changed, 13 insertions, 94 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index 2ac9a5dac9..5f268dbf35 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -86,20 +86,13 @@
#include "private/qthread_p.h"
#include "private/qguiapplication_p.h"
#include <qdebug.h>
-
-#undef slots
-#include <Cocoa/Cocoa.h>
-#include <Carbon/Carbon.h>
+#include "qcocoahelpers.h"
+#include "qcocoaapplication.h"
QT_BEGIN_NAMESPACE
QT_USE_NAMESPACE
-enum {
- QtCocoaEventSubTypeWakeup = SHRT_MAX,
- QtCocoaEventSubTypePostMessage = SHRT_MAX-1
-};
-
static inline CFRunLoopRef mainRunLoop()
{
return CFRunLoopGetMain();
@@ -377,53 +370,17 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
if (!excludeUserEvents) {
while (!d->queuedUserInputEvents.isEmpty()) {
event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst());
- if (!filterNativeEvent("NSEvent", event, 0)) {
- [NSApp sendEvent:event];
+ if ([NSApp qt_filterOrSendEvent:event])
retVal = true;
- }
[event release];
}
}
- // If Qt is used as a plugin, or as an extension in a native cocoa
- // application, we should not run or stop NSApplication; This will be
- // done from the application itself. And if processEvents is called
- // manually (rather than from a QEventLoop), we cannot enter a tight
- // loop and block this call, but instead we need to return after one flush.
- // 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 = (!excludeUserEvents
- && ((d->processEventsFlags & QEventLoop::DialogExec)
- || (d->processEventsFlags & QEventLoop::EventLoopExec)));
-
- if (canExec_Qt && canExec_3rdParty) {
- // We can use exec-mode, meaning that we can stay in a tight loop until
- // interrupted. This is mostly an optimization, but it allow us to use
- // [NSApp run], which is the normal code path for cocoa applications.
- if (NSModalSession session = d->currentModalSession()) {
- QBoolBlocker execGuard(d->currentExecIsNSAppRun, false);
- while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt)
- qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
-
- if (!d->interrupt && session == d->currentModalSessionCached) {
- // 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();
- }
- } else {
- d->nsAppRunCalledByQt = true;
- QBoolBlocker execGuard(d->currentExecIsNSAppRun, true);
- [NSApp run];
- }
- retVal = true;
- } else {
+ {
int lastSerialCopy = d->lastSerial;
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();
if (NSModalSession session = d->currentModalSession()) {
// INVARIANT: a modal window is executing.
if (!excludeUserEvents) {
@@ -444,9 +401,9 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// this case, we need more control over which events gets dispatched, and
// cannot use [NSApp runModalSession:session]:
event = [NSApp nextEventMatchingMask:NSAnyEventMask
- untilDate:nil
- inMode:NSModalPanelRunLoopMode
- dequeue: YES];
+ untilDate:nil
+ inMode:NSModalPanelRunLoopMode
+ dequeue:YES];
if (event) {
if (IsMouseOrKeyEvent(event)) {
@@ -454,18 +411,16 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
d->queuedUserInputEvents.append(event);
continue;
}
- if (!filterNativeEvent("NSEvent", event, 0)) {
- [NSApp sendEvent:event];
+ if ([NSApp qt_filterOrSendEvent:event])
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];
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
if (event) {
if (flags & QEventLoop::ExcludeUserInputEvents) {
@@ -475,10 +430,8 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
continue;
}
}
- if (!filterNativeEvent("NSEvent", event, 0)) {
- [NSApp sendEvent:event];
+ if ([NSApp qt_filterOrSendEvent:event])
retVal = true;
- }
}
} while (!d->interrupt && event != nil);
@@ -557,26 +510,6 @@ void QCocoaEventDispatcher::wakeUp()
QEventDispatcherMac Implementation
*****************************************************************************/
-void QCocoaEventDispatcherPrivate::ensureNSAppInitialized()
-{
- // Some elements in Cocoa require NSApplication to be running before
- // they get fully initialized, in particular the menu bar. This
- // function is intended for cases where a dialog is told to execute before
- // QGuiApplication::exec is called, or the application spins the events loop
- // manually rather than calling QGuiApplication:exec.
- // The function makes sure that NSApplication starts running, but stops
- // it again as soon as the send posted events callback is called. That way
- // we let Cocoa finish the initialization it seems to need. We'll only
- // apply this trick at most once for any application, and we avoid doing it
- // for the common case where main just starts QGuiApplication::exec.
- if (nsAppRunCalledByQt || [NSApp isRunning])
- return;
- nsAppRunCalledByQt = true;
- QBoolBlocker block1(interrupt, true);
- QBoolBlocker block2(currentExecIsNSAppRun, true);
- [NSApp run];
-}
-
void QCocoaEventDispatcherPrivate::temporarilyStopAllModalSessions()
{
// Flush, and Stop, all created modal session, and as
@@ -621,7 +554,6 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
if (!nswindow)
continue;
- ensureNSAppInitialized();
QBoolBlocker block1(blockSendPostedEvents, true);
info.nswindow = nswindow;
[(NSWindow*) info.nswindow retain];
@@ -766,8 +698,6 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
: processEventsFlags(0),
runLoopTimerRef(0),
blockSendPostedEvents(false),
- currentExecIsNSAppRun(false),
- nsAppRunCalledByQt(false),
cleanupModalSessionsNeeded(false),
currentModalSessionCached(0),
lastSerial(-1),
@@ -858,19 +788,8 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
if (cleanupModalSessionsNeeded)
cleanupModalSessions();
- if (interrupt) {
- if (currentExecIsNSAppRun) {
- // The event dispatcher has been interrupted. But since
- // [NSApplication run] is running the event loop, we
- // delayed stopping it until now (to let cocoa process
- // pending cocoa events first).
- if (currentModalSessionCached)
- temporarilyStopAllModalSessions();
- [NSApp stop:NSApp];
- cancelWaitForMoreEvents();
- }
+ if (interrupt)
return;
- }
int serial = serialNumber.load();
if (!threadData->canWait || (serial != lastSerial)) {