summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mkspecs/features/mac/default_post.prf14
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro110
-rw-r--r--src/plugins/platforms/cocoa/cocoamain.pro19
-rw-r--r--src/plugins/platforms/cocoa/cocoaplugin.pro109
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.mm46
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm77
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm107
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintrospection.mm50
-rw-r--r--src/plugins/platforms/cocoa/qcocoamain.mm181
13 files changed, 384 insertions, 347 deletions
diff --git a/mkspecs/features/mac/default_post.prf b/mkspecs/features/mac/default_post.prf
index b183814e63..4de0423f33 100644
--- a/mkspecs/features/mac/default_post.prf
+++ b/mkspecs/features/mac/default_post.prf
@@ -1,6 +1,20 @@
load(default_post)
!no_objective_c:CONFIG += objective_c
+
+equals(TEMPLATE, app):qt: {
+ deps = $$replace(QT, -private$, )
+ deps = $$resolve_depends(deps, "QT.", ".depends" ".private_depends" ".run_depends")
+ contains(deps, gui): {
+ DEFINES += QT_NEEDS_QMAIN
+ CONFIG += link_prl
+ # When CI'ing Qt we still need to link against libqtcocoamain.a, even before deployment.
+ # Hence the /get variable, suffix which looks for the libraries location effective path.
+ QMAKE_LIBDIR += $$[QT_INSTALL_LIBS/get]
+ QMAKE_LIBS += -lqtcocoamain
+ }
+}
+
qt:!isEmpty(QT_CONFIG) {
# Pick a suitable default architecture for qmake-based applications.
# If the Qt package contains one of x86 and x86_64, pick that one. If it
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index a2fd8c0613..dd13882f8c 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -1,109 +1,7 @@
-TARGET = qcocoa
+TEMPLATE = subdirs
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin
-load(qt_plugin)
+cocoamain.file = cocoamain.pro
+cocoaplugin.file = cocoaplugin.pro
-OBJECTIVE_SOURCES += main.mm \
- qcocoaintegration.mm \
- qcocoatheme.mm \
- qcocoabackingstore.mm \
- qcocoawindow.mm \
- qnsview.mm \
- qnsviewaccessibility.mm \
- qcocoaautoreleasepool.mm \
- qnswindowdelegate.mm \
- qcocoaglcontext.mm \
- qcocoanativeinterface.mm \
- qcocoaeventdispatcher.mm \
- qcocoaapplicationdelegate.mm \
- qcocoaapplication.mm \
- qcocoamenu.mm \
- qcocoamenuitem.mm \
- qcocoamenubar.mm \
- qcocoamenuloader.mm \
- qcocoahelpers.mm \
- qmultitouch_mac.mm \
- qcocoaaccessibilityelement.mm \
- qcocoaaccessibility.mm \
- qcocoacolordialoghelper.mm \
- qcocoafiledialoghelper.mm \
- qcocoafontdialoghelper.mm \
- qcocoacursor.mm \
- qcocoaclipboard.mm \
- qcocoadrag.mm \
- qmacclipboard.mm \
- qmacmime.mm \
- qcocoasystemsettings.mm \
- qcocoainputcontext.mm \
- qcocoaservices.mm \
- qcocoasystemtrayicon.mm \
- qcocoaintrospection.mm \
- qcocoakeymapper.mm \
+SUBDIRS = cocoamain cocoaplugin
-SOURCES += messages.cpp
-
-HEADERS += qcocoaintegration.h \
- qcocoatheme.h \
- qcocoabackingstore.h \
- qcocoawindow.h \
- qnsview.h \
- qcocoaautoreleasepool.h \
- qnswindowdelegate.h \
- qcocoaglcontext.h \
- qcocoanativeinterface.h \
- qcocoaeventdispatcher.h \
- qcocoaapplicationdelegate.h \
- qcocoaapplication.h \
- qcocoamenu.h \
- qcocoamenuitem.h \
- qcocoamenubar.h \
- qcocoamenuloader.h \
- qcocoahelpers.h \
- qmultitouch_mac_p.h \
- qcocoaaccessibilityelement.h \
- qcocoaaccessibility.h \
- qcocoacolordialoghelper.h \
- qcocoafiledialoghelper.h \
- qcocoafontdialoghelper.h \
- qcocoacursor.h \
- qcocoaclipboard.h \
- qcocoadrag.h \
- qmacclipboard.h \
- qmacmime.h \
- qcocoasystemsettings.h \
- qcocoainputcontext.h \
- qcocoaservices.h \
- qcocoasystemtrayicon.h \
- qcocoaintrospection.h \
- qcocoakeymapper.h \
- messages.h
-
-RESOURCES += qcocoaresources.qrc
-
-LIBS += -framework Cocoa -framework Carbon -framework IOKit
-
-QT += core-private gui-private platformsupport-private
-
-qtHaveModule(widgets) {
- OBJECTIVE_SOURCES += \
- qpaintengine_mac.mm \
- qprintengine_mac.mm \
- qcocoaprintersupport.mm \
-
- HEADERS += \
- qpaintengine_mac_p.h \
- qprintengine_mac_p.h \
- qcocoaprintersupport.h \
-
- QT += widgets-private printsupport-private
-}
-
-OTHER_FILES += cocoa.json
-
-# Acccessibility debug support
-# DEFINES += QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
-# include ($$PWD/../../../../util/accessibilityinspector/accessibilityinspector.pri)
-
-# Window debug support
-#DEFINES += QT_COCOA_ENABLE_WINDOW_DEBUG
diff --git a/src/plugins/platforms/cocoa/cocoamain.pro b/src/plugins/platforms/cocoa/cocoamain.pro
new file mode 100644
index 0000000000..8065f8b785
--- /dev/null
+++ b/src/plugins/platforms/cocoa/cocoamain.pro
@@ -0,0 +1,19 @@
+# Additional Qt project file for qtmain lib on OS X
+!macx:error("$$_FILE_ is intended only for OS X!")
+
+TEMPLATE = lib
+TARGET = qtcocoamain
+DESTDIR = $$QT.core.libs
+
+CONFIG += staticlib release
+
+QT = core-private gui-private
+LIBS += -framework Cocoa
+
+HEADERS = qcocoaintrospection.h
+
+OBJECTIVE_SOURCES = qcocoamain.mm \
+ qcocoaintrospection.mm
+
+load(qt_installs)
+load(qt_targets)
diff --git a/src/plugins/platforms/cocoa/cocoaplugin.pro b/src/plugins/platforms/cocoa/cocoaplugin.pro
new file mode 100644
index 0000000000..a2fd8c0613
--- /dev/null
+++ b/src/plugins/platforms/cocoa/cocoaplugin.pro
@@ -0,0 +1,109 @@
+TARGET = qcocoa
+
+PLUGIN_TYPE = platforms
+PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin
+load(qt_plugin)
+
+OBJECTIVE_SOURCES += main.mm \
+ qcocoaintegration.mm \
+ qcocoatheme.mm \
+ qcocoabackingstore.mm \
+ qcocoawindow.mm \
+ qnsview.mm \
+ qnsviewaccessibility.mm \
+ qcocoaautoreleasepool.mm \
+ qnswindowdelegate.mm \
+ qcocoaglcontext.mm \
+ qcocoanativeinterface.mm \
+ qcocoaeventdispatcher.mm \
+ qcocoaapplicationdelegate.mm \
+ qcocoaapplication.mm \
+ qcocoamenu.mm \
+ qcocoamenuitem.mm \
+ qcocoamenubar.mm \
+ qcocoamenuloader.mm \
+ qcocoahelpers.mm \
+ qmultitouch_mac.mm \
+ qcocoaaccessibilityelement.mm \
+ qcocoaaccessibility.mm \
+ qcocoacolordialoghelper.mm \
+ qcocoafiledialoghelper.mm \
+ qcocoafontdialoghelper.mm \
+ qcocoacursor.mm \
+ qcocoaclipboard.mm \
+ qcocoadrag.mm \
+ qmacclipboard.mm \
+ qmacmime.mm \
+ qcocoasystemsettings.mm \
+ qcocoainputcontext.mm \
+ qcocoaservices.mm \
+ qcocoasystemtrayicon.mm \
+ qcocoaintrospection.mm \
+ qcocoakeymapper.mm \
+
+SOURCES += messages.cpp
+
+HEADERS += qcocoaintegration.h \
+ qcocoatheme.h \
+ qcocoabackingstore.h \
+ qcocoawindow.h \
+ qnsview.h \
+ qcocoaautoreleasepool.h \
+ qnswindowdelegate.h \
+ qcocoaglcontext.h \
+ qcocoanativeinterface.h \
+ qcocoaeventdispatcher.h \
+ qcocoaapplicationdelegate.h \
+ qcocoaapplication.h \
+ qcocoamenu.h \
+ qcocoamenuitem.h \
+ qcocoamenubar.h \
+ qcocoamenuloader.h \
+ qcocoahelpers.h \
+ qmultitouch_mac_p.h \
+ qcocoaaccessibilityelement.h \
+ qcocoaaccessibility.h \
+ qcocoacolordialoghelper.h \
+ qcocoafiledialoghelper.h \
+ qcocoafontdialoghelper.h \
+ qcocoacursor.h \
+ qcocoaclipboard.h \
+ qcocoadrag.h \
+ qmacclipboard.h \
+ qmacmime.h \
+ qcocoasystemsettings.h \
+ qcocoainputcontext.h \
+ qcocoaservices.h \
+ qcocoasystemtrayicon.h \
+ qcocoaintrospection.h \
+ qcocoakeymapper.h \
+ messages.h
+
+RESOURCES += qcocoaresources.qrc
+
+LIBS += -framework Cocoa -framework Carbon -framework IOKit
+
+QT += core-private gui-private platformsupport-private
+
+qtHaveModule(widgets) {
+ OBJECTIVE_SOURCES += \
+ qpaintengine_mac.mm \
+ qprintengine_mac.mm \
+ qcocoaprintersupport.mm \
+
+ HEADERS += \
+ qpaintengine_mac_p.h \
+ qprintengine_mac_p.h \
+ qcocoaprintersupport.h \
+
+ QT += widgets-private printsupport-private
+}
+
+OTHER_FILES += cocoa.json
+
+# Acccessibility debug support
+# DEFINES += QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
+# include ($$PWD/../../../../util/accessibilityinspector/accessibilityinspector.pri)
+
+# Window debug support
+#DEFINES += QT_COCOA_ENABLE_WINDOW_DEBUG
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h
index ffb12ea846..b01f3ca93e 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.h
@@ -102,13 +102,9 @@
- (void)qt_sendPostedMessage:(NSEvent *)event;
- (BOOL)qt_filterEvent:(NSEvent *)event;
+- (BOOL)qt_filterOrSendEvent:(NSEvent *)event;
@end
-@interface QT_MANGLE_NAMESPACE(QNSApplication) : NSApplication {
-}
-@end
-
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSApplication);
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm
index c293f4cd52..cf9644fe9b 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -83,6 +83,8 @@
QT_USE_NAMESPACE
+static SEL qt_sendEvent_original_SEL = @selector(qt_sendEvent_original:);
+
@implementation NSApplication (QT_MANGLE_NAMESPACE(QApplicationIntegration))
- (void)QT_MANGLE_NAMESPACE(qt_setDockMenu):(NSMenu *)newMenu
@@ -153,34 +155,22 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE
return false;
}
-@end
-
-@implementation QNSApplication
-
-- (void)qt_sendEvent_original:(NSEvent *)event
+- (BOOL)qt_filterOrSendEvent:(NSEvent *)event
{
- Q_UNUSED(event);
- // This method will only be used as a signature
- // template for the method we add into NSApplication
- // containing the original [NSApplication sendEvent:] implementation
+ if ([self qt_filterEvent:event])
+ return false;
+
+ Q_ASSERT_X([self respondsToSelector:qt_sendEvent_original_SEL], "qt_filterOrSendEvent:",
+ "Running event loop before calling qt_redirectNSApplicationSendEvent()");
+ [self performSelector:qt_sendEvent_original_SEL withObject:event];
+ return true;
}
- (void)qt_sendEvent_replacement:(NSEvent *)event
{
// This method (or its implementation to be precise) will
- // be called instead of sendEvent if redirection occurs.
- // 'self' will then be an instance of NSApplication
- // (and not QNSApplication)
- if (![NSApp qt_filterEvent:event])
- [self qt_sendEvent_original:event];
-}
-
-- (void)sendEvent:(NSEvent *)event
-{
- // This method will be called if
- // no redirection occurs
- if (![NSApp qt_filterEvent:event])
- [super sendEvent:event];
+ // be called instead of sendEvent: after redirection occurs.
+ [self qt_filterOrSendEvent:event];
}
@end
@@ -189,22 +179,16 @@ QT_BEGIN_NAMESPACE
void qt_redirectNSApplicationSendEvent()
{
- if ([NSApp isMemberOfClass:[QNSApplication class]]) {
- // No need to change implementation since Qt
- // already controls a subclass of NSApplication
- return;
- }
-
// Change the implementation of [NSApplication sendEvent] to the
- // implementation of qt_sendEvent_replacement found in QNSApplication.
+ // implementation of qt_sendEvent_replacement.
// And keep the old implementation that gets overwritten inside a new
// method 'qt_sendEvent_original' that we add to NSApplication
qt_cocoa_change_implementation(
[NSApplication class],
@selector(sendEvent:),
- [QNSApplication class],
+ [NSApplication class],
@selector(qt_sendEvent_replacement:),
- @selector(qt_sendEvent_original:));
+ qt_sendEvent_original_SEL);
}
void qt_resetNSApplicationSendEvent()
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 7f6c4224df..8ffab71eec 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -99,15 +99,13 @@
NSMenu *dockMenu;
QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *qtMenuLoader;
NSObject <NSApplicationDelegate> *reflectionDelegate;
- bool inLaunch;
}
+ (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate;
- (void)setDockMenu:(NSMenu *)newMenu;
- (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader)*)menuLoader;
- (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader;
- (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate;
-- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
-- (void) removeAppleEventHandlers;
+- (NSObject<NSApplicationDelegate> *)reflectionDelegate;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 423d552627..7e0fb62dcf 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -101,7 +101,6 @@ static void cleanupCocoaApplicationDelegate()
{
self = [super init];
if (self) {
- inLaunch = true;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateScreens:)
@@ -241,55 +240,6 @@ static void cleanupCocoaApplicationDelegate()
return NSTerminateCancel;
}
-- (void) applicationWillFinishLaunching:(NSNotification *)notification
-{
- Q_UNUSED(notification);
-
- /*
- From the Cocoa documentation: "A good place to install event handlers
- is in the applicationWillFinishLaunching: method of the application
- delegate. At that point, the Application Kit has installed its default
- event handlers, so if you install a handler for one of the same events,
- it will replace the Application Kit version."
- */
-
- /*
- If Qt is used as a plugin, we let the 3rd party application handle
- events like quit and open file events. Otherwise, if we install our own
- handlers, we easily end up breaking functionality the 3rd party
- application depends on.
- */
- NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
- [eventManager setEventHandler:self
- andSelector:@selector(appleEventQuit:withReplyEvent:)
- forEventClass:kCoreEventClass
- andEventID:kAEQuitApplication];
- [eventManager setEventHandler:self
- andSelector:@selector(getUrl:withReplyEvent:)
- forEventClass:kInternetEventClass
- andEventID:kAEGetURL];
-}
-
-// called by QCocoaIntegration's destructor before resetting the application delegate to nil
-- (void) removeAppleEventHandlers
-{
- NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
- [eventManager removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEQuitApplication];
- [eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
-}
-
-- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
-{
- Q_UNUSED(aNotification);
- inLaunch = false;
- // qt_release_apple_event_handler();
-
-
- // Insert code here to initialize your application
-}
-
-
-
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
{
Q_UNUSED(filenames);
@@ -297,14 +247,6 @@ static void cleanupCocoaApplicationDelegate()
for (NSString *fileName in filenames) {
QString qtFileName = QCFString::toQString(fileName);
- if (inLaunch) {
- // We need to be careful because Cocoa will be nice enough to take
- // command line arguments and send them to us as events. Given the history
- // of Qt Applications, this will result in behavior people don't want, as
- // they might be doing the opening themselves with the command line parsing.
- if (qApp->arguments().contains(qtFileName))
- continue;
- }
QWindowSystemInterface::handleFileOpenEvent(qtFileName);
}
@@ -367,6 +309,11 @@ static void cleanupCocoaApplicationDelegate()
*/
}
+- (NSObject<NSApplicationDelegate> *)reflectionDelegate
+{
+ return reflectionDelegate;
+}
+
- (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate
{
[oldDelegate retain];
@@ -400,20 +347,6 @@ static void cleanupCocoaApplicationDelegate()
[self doesNotRecognizeSelector:invocationSelector];
}
-- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
-{
- Q_UNUSED(replyEvent);
- NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
- QWindowSystemInterface::handleFileOpenEvent(QCFString::toQString(urlString));
-}
-
-- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
-{
- Q_UNUSED(event);
- Q_UNUSED(replyEvent);
- [NSApp terminate:self];
-}
-
- (void)qtDispatcherToQAction:(id)sender
{
Q_UNUSED(sender);
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index 93476ee1b4..550460a3e1 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -162,8 +162,6 @@ public:
bool blockSendPostedEvents;
// The following variables help organizing modal sessions:
QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
- bool currentExecIsNSAppRun;
- bool nsAppRunCalledByQt;
bool cleanupModalSessionsNeeded;
NSModalSession currentModalSessionCached;
NSModalSession currentModalSession();
@@ -175,7 +173,6 @@ public:
void cancelWaitForMoreEvents();
void maybeCancelWaitForMoreEvents();
- void ensureNSAppInitialized();
QCFSocketNotifier cfSocketNotifier;
QList<void *> queuedUserInputEvents; // NSEvent *
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)) {
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 6d1882f622..ef242195c0 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -232,7 +232,7 @@ QCocoaIntegration::QCocoaIntegration()
qApp->setAttribute(Qt::AA_DontUseNativeMenuBar, false);
- NSApplication *cocoaApplication = [QNSApplication sharedApplication];
+ NSApplication *cocoaApplication = NSApp;
qt_redirectNSApplicationSendEvent();
if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
@@ -280,9 +280,8 @@ QCocoaIntegration::~QCocoaIntegration()
if (!QCoreApplication::testAttribute(Qt::AA_MacPluginApplication)) {
// remove the apple event handlers installed by QCocoaApplicationDelegate
QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate];
- [delegate removeAppleEventHandlers];
// reset the application delegate
- [[NSApplication sharedApplication] setDelegate: 0];
+ [[NSApplication sharedApplication] setDelegate:[delegate reflectionDelegate]];
}
// Delete the clipboard integration and destroy mime type converters.
diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.mm b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
index 806effc929..654ed68e26 100644
--- a/src/plugins/platforms/cocoa/qcocoaintrospection.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
@@ -79,43 +79,33 @@ QT_BEGIN_NAMESPACE
void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel, SEL backupSel)
{
-#ifndef QT_MAC_USE_COCOA
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
-#endif
- {
- // The following code replaces the _implementation_ for the selector we want to hack
- // (originalSel) with the implementation found in proxyClass. Then it creates
- // a new 'backup' method inside baseClass containing the old, original,
- // implementation (fakeSel). You can let the proxy implementation of originalSel
- // call fakeSel if needed (similar approach to calling a super class implementation).
- // fakeSel must also be implemented in proxyClass, as the signature is used
- // as template for the method one we add into baseClass.
- // NB: You will typically never create any instances of proxyClass; we use it
- // only for stealing its contents and put it into baseClass.
- if (!replacementSel)
- replacementSel = originalSel;
+ // The following code replaces the _implementation_ for the selector we want to hack
+ // (originalSel) with the implementation found in proxyClass. Then it creates
+ // a new 'backup' method inside baseClass containing the old, original,
+ // implementation (fakeSel). You can let the proxy implementation of originalSel
+ // call fakeSel if needed (similar approach to calling a super class implementation).
+ // fakeSel must also be implemented in proxyClass, as the signature is used
+ // as template for the method one we add into baseClass.
+ // NB: You will typically never create any instances of proxyClass; we use it
+ // only for stealing its contents and put it into baseClass.
+ if (!replacementSel)
+ replacementSel = originalSel;
- Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
- Method replacementMethod = class_getInstanceMethod(proxyClass, replacementSel);
- IMP originalImp = method_setImplementation(originalMethod, method_getImplementation(replacementMethod));
+ Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
+ Method replacementMethod = class_getInstanceMethod(proxyClass, replacementSel);
+ IMP originalImp = method_setImplementation(originalMethod, method_getImplementation(replacementMethod));
- if (backupSel) {
- Method backupMethod = class_getInstanceMethod(proxyClass, backupSel);
- class_addMethod(baseClass, backupSel, originalImp, method_getTypeEncoding(backupMethod));
- }
+ if (backupSel) {
+ Method backupMethod = class_getInstanceMethod(proxyClass, backupSel);
+ class_addMethod(baseClass, backupSel, originalImp, method_getTypeEncoding(backupMethod));
}
}
void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL backupSel)
{
-#ifndef QT_MAC_USE_COCOA
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
-#endif
- {
- Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
- Method backupMethodInBaseClass = class_getInstanceMethod(baseClass, backupSel);
- method_setImplementation(originalMethod, method_getImplementation(backupMethodInBaseClass));
- }
+ Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
+ Method backupMethodInBaseClass = class_getInstanceMethod(baseClass, backupSel);
+ method_setImplementation(originalMethod, method_getImplementation(backupMethodInBaseClass));
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamain.mm b/src/plugins/platforms/cocoa/qcocoamain.mm
new file mode 100644
index 0000000000..51d27e0c72
--- /dev/null
+++ b/src/plugins/platforms/cocoa/qcocoamain.mm
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <Cocoa/Cocoa.h>
+#include <QtGui/qpa/qwindowsysteminterface.h>
+#include <QtCore/private/qcore_mac_p.h>
+#include "qcocoaintrospection.h"
+
+extern int qMain(int argc, char *argv[]);
+
+@interface QCocoaMainWrapper : NSObject
+
+- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
+- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
+- (void)runUserMain;
+
+@end
+
+@implementation QCocoaMainWrapper
+
+- (void)applicationWillFinishLaunching:(NSNotification *)notification
+{
+ if ([notification object] != NSApp) // Shouldn't happen AFAIK, but still
+ return;
+
+ /*
+ From the Cocoa documentation: "A good place to install event handlers
+ is in the applicationWillFinishLaunching: method of the application
+ delegate. At that point, the Application Kit has installed its default
+ event handlers, so if you install a handler for one of the same events,
+ it will replace the Application Kit version."
+ */
+
+ /*
+ If Qt is used as a plugin, we let the 3rd party application handle
+ events like quit and open file events. Otherwise, if we install our own
+ handlers, we easily end up breaking functionality the 3rd party
+ application depends on.
+ */
+ NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
+ [eventManager setEventHandler:self
+ andSelector:@selector(appleEventQuit:withReplyEvent:)
+ forEventClass:kCoreEventClass
+ andEventID:kAEQuitApplication];
+ [eventManager setEventHandler:self
+ andSelector:@selector(getUrl:withReplyEvent:)
+ forEventClass:kInternetEventClass
+ andEventID:kAEGetURL];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notification
+{
+ if ([notification object] != NSApp) // Shouldn't happen AFAIK, but still
+ return;
+
+ // We schedule the main-redirection for the next eventloop pass so that we
+ // can return from this function and let NSApplicationMain finish its job.
+ [NSTimer scheduledTimerWithTimeInterval:0 target:self
+ selector:@selector(runUserMain) userInfo:nil repeats:NO];
+}
+
+- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
+{
+ Q_UNUSED(replyEvent);
+ NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
+ QWindowSystemInterface::handleFileOpenEvent(QCFString::toQString(urlString));
+}
+
+- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
+{
+ Q_UNUSED(event);
+ Q_UNUSED(replyEvent);
+ [NSApp terminate:self];
+}
+
+- (void)runUserMain
+{
+ NSArray *arguments = [[NSProcessInfo processInfo] arguments];
+ int argc = arguments.count;
+ char **argv = new char*[argc];
+ for (int i = 0; i < argc; ++i) {
+ NSString *arg = [arguments objectAtIndex:i];
+ argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]]));
+ strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]);
+ }
+
+ qMain(argc, argv);
+ delete[] argv;
+
+ NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
+ [eventManager removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEQuitApplication];
+ [eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
+
+ [NSApp terminate:self];
+}
+
+@end
+
+static SEL qt_infoDictionary_original_SEL = @selector(qt_infoDictionary_original);
+
+@implementation NSBundle (QT_MANGLE_NAMESPACE(QCocoaMain))
+
+- (Class)qt_infoDictionary_replacement
+{
+ if (self == [NSBundle mainBundle]) {
+ static NSMutableDictionary *infoDict = nil;
+ if (!infoDict) {
+ infoDict = [[self performSelector:qt_infoDictionary_original_SEL] mutableCopy];
+ [infoDict setValue:@"NSApplication" forKey:@"NSPrincipalClass"];
+ }
+ return infoDict;
+ }
+
+ return [self performSelector:qt_infoDictionary_original_SEL];
+}
+
+@end
+
+int main(int argc, char *argv[])
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ QCocoaMainWrapper *mainWrapper = [[QCocoaMainWrapper alloc] init];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:mainWrapper selector:@selector(applicationWillFinishLaunching:)
+ name:NSApplicationWillFinishLaunchingNotification object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:mainWrapper selector:@selector(applicationDidFinishLaunching:)
+ name:NSApplicationDidFinishLaunchingNotification object:nil];
+
+ NSBundle *mainBundle = [NSBundle mainBundle];
+ if (!mainBundle.principalClass) {
+ // Since several of the GUI based Qt utilities (e.g., qmlscene) are command
+ // line applications, meaning non-bundle applications, we need to make Cocoa
+ // believe everything is fine. So we fake the main bundle's dictionary by
+ // adding the "NSPrincipalClass" property. So far, this seems to be enough to
+ // keep NSApplicationMain() happy and running...
+ qt_cocoa_change_implementation([NSBundle class], @selector(infoDictionary),
+ [NSBundle class], @selector(qt_infoDictionary_replacement), qt_infoDictionary_original_SEL);
+ }
+
+ return NSApplicationMain(argc, (const char **)argv);
+}