summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorMorten Johan Sørvig <morten.sorvig@digia.com>2013-09-02 09:30:26 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-02 13:07:35 +0200
commit8fc97fdfc76fc62e1faa23f8b768d1ec303329d4 (patch)
tree3991bf746691a6c33615718dd05f6e23b9795ec6 /src/plugins
parent585758389c64e556ef4808308dee27e19241581e (diff)
Revert Mac event loop changes.
"Make QGuiApplication::exec() run within NSApplicationMain()" "Make Qt process native and timer events on Cocoa applications" "Cocoa: Fix QFontDialog, QColorDialog auto-tests" This reverts commits 1e14762b8d79118540bd09a84dd3e48f4f5e113e e4b2a0b4bab2a17a65fedafe9bae50af1fe019f6 df7944e7d7dd8b2bbccbd639eff0ab09745d6cc3 Change-Id: I80b65b5ee0297b090f807bd420664233dfc44f7b Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com> Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/plugins')
-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/qcocoacolordialoghelper.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm20
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm117
-rw-r--r--src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm4
-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
15 files changed, 357 insertions, 396 deletions
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index dd13882f8c..a2fd8c0613 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -1,7 +1,109 @@
-TEMPLATE = subdirs
+TARGET = qcocoa
-cocoamain.file = cocoamain.pro
-cocoaplugin.file = cocoaplugin.pro
+PLUGIN_TYPE = platforms
+PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin
+load(qt_plugin)
-SUBDIRS = cocoamain cocoaplugin
+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/cocoamain.pro b/src/plugins/platforms/cocoa/cocoamain.pro
deleted file mode 100644
index 8065f8b785..0000000000
--- a/src/plugins/platforms/cocoa/cocoamain.pro
+++ /dev/null
@@ -1,19 +0,0 @@
-# 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
deleted file mode 100644
index a2fd8c0613..0000000000
--- a/src/plugins/platforms/cocoa/cocoaplugin.pro
+++ /dev/null
@@ -1,109 +0,0 @@
-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 b01f3ca93e..ffb12ea846 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.h
@@ -102,9 +102,13 @@
- (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 cf9644fe9b..c293f4cd52 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -83,8 +83,6 @@
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
@@ -155,22 +153,34 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE
return false;
}
-- (BOOL)qt_filterOrSendEvent:(NSEvent *)event
-{
- if ([self qt_filterEvent:event])
- return false;
+@end
- 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;
+@implementation QNSApplication
+
+- (void)qt_sendEvent_original:(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
}
- (void)qt_sendEvent_replacement:(NSEvent *)event
{
// This method (or its implementation to be precise) will
- // be called instead of sendEvent: after redirection occurs.
- [self qt_filterOrSendEvent:event];
+ // 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];
}
@end
@@ -179,16 +189,22 @@ 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.
+ // implementation of qt_sendEvent_replacement found in QNSApplication.
// 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:),
- [NSApplication class],
+ [QNSApplication class],
@selector(qt_sendEvent_replacement:),
- qt_sendEvent_original_SEL);
+ @selector(qt_sendEvent_original:));
}
void qt_resetNSApplicationSendEvent()
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 8ffab71eec..7f6c4224df 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -99,13 +99,15 @@
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;
-- (NSObject<NSApplicationDelegate> *)reflectionDelegate;
+- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
+- (void) removeAppleEventHandlers;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 7e0fb62dcf..423d552627 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -101,6 +101,7 @@ static void cleanupCocoaApplicationDelegate()
{
self = [super init];
if (self) {
+ inLaunch = true;
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateScreens:)
@@ -240,6 +241,55 @@ 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);
@@ -247,6 +297,14 @@ 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);
}
@@ -309,11 +367,6 @@ static void cleanupCocoaApplicationDelegate()
*/
}
-- (NSObject<NSApplicationDelegate> *)reflectionDelegate
-{
- return reflectionDelegate;
-}
-
- (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate
{
[oldDelegate retain];
@@ -347,6 +400,20 @@ 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/qcocoacolordialoghelper.h b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
index 2b34f909d1..59e029769d 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h
@@ -59,8 +59,6 @@ public:
void setCurrentColor(const QColor&);
QColor currentColor() const;
-
- bool event(QEvent *);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
index ef2b4cbcfb..d90d77ec1d 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
@@ -161,10 +161,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
- (void)closePanel
{
- if (mDialogIsExecuting) {
- mDialogIsExecuting = false;
- [NSApp stopModal];
- }
[mColorPanel close];
}
@@ -492,22 +488,6 @@ QColor QCocoaColorDialogHelper::currentColor() const
return sharedColorPanel()->currentColor();
}
-bool QCocoaColorDialogHelper::event(QEvent *e)
-{
- if (e->type() == QEvent::KeyPress) {
- QKeyEvent *ke = static_cast<QKeyEvent *>(e);
- if (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return) {
- emit accept();
- return true;
- } else if (ke->key() == Qt::Key_Escape) {
- emit reject();
- return true;
- }
- }
-
- return false;
-}
-
QT_END_NAMESPACE
#endif // QT_NO_COLORDIALOG
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index 550460a3e1..93476ee1b4 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -162,6 +162,8 @@ public:
bool blockSendPostedEvents;
// The following variables help organizing modal sessions:
QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
+ bool currentExecIsNSAppRun;
+ bool nsAppRunCalledByQt;
bool cleanupModalSessionsNeeded;
NSModalSession currentModalSessionCached;
NSModalSession currentModalSession();
@@ -173,6 +175,7 @@ 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 c236243438..2ac9a5dac9 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -86,13 +86,20 @@
#include "private/qthread_p.h"
#include "private/qguiapplication_p.h"
#include <qdebug.h>
-#include "qcocoahelpers.h"
-#include "qcocoaapplication.h"
+
+#undef slots
+#include <Cocoa/Cocoa.h>
+#include <Carbon/Carbon.h>
QT_BEGIN_NAMESPACE
QT_USE_NAMESPACE
+enum {
+ QtCocoaEventSubTypeWakeup = SHRT_MAX,
+ QtCocoaEventSubTypePostMessage = SHRT_MAX-1
+};
+
static inline CFRunLoopRef mainRunLoop()
{
return CFRunLoopGetMain();
@@ -111,6 +118,11 @@ static Boolean runLoopSourceEqualCallback(const void *info1, const void *info2)
void QCocoaEventDispatcherPrivate::runLoopTimerCallback(CFRunLoopTimerRef, void *info)
{
QCocoaEventDispatcherPrivate *d = static_cast<QCocoaEventDispatcherPrivate *>(info);
+ if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) {
+ // processEvents() was called "manually," ignore this source for now
+ d->maybeCancelWaitForMoreEvents();
+ return;
+ }
CFRunLoopSourceSignal(d->activateTimersSourceRef);
}
@@ -365,17 +377,53 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
if (!excludeUserEvents) {
while (!d->queuedUserInputEvents.isEmpty()) {
event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst());
- if ([NSApp qt_filterOrSendEvent:event])
+ if (!filterNativeEvent("NSEvent", event, 0)) {
+ [NSApp sendEvent: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) {
@@ -396,9 +444,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)) {
@@ -406,16 +454,18 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
d->queuedUserInputEvents.append(event);
continue;
}
- if ([NSApp qt_filterOrSendEvent:event])
+ if (!filterNativeEvent("NSEvent", event, 0)) {
+ [NSApp sendEvent: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) {
@@ -425,8 +475,10 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
continue;
}
}
- if ([NSApp qt_filterOrSendEvent:event])
+ if (!filterNativeEvent("NSEvent", event, 0)) {
+ [NSApp sendEvent:event];
retVal = true;
+ }
}
} while (!d->interrupt && event != nil);
@@ -505,6 +557,26 @@ 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
@@ -549,6 +621,7 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
if (!nswindow)
continue;
+ ensureNSAppInitialized();
QBoolBlocker block1(blockSendPostedEvents, true);
info.nswindow = nswindow;
[(NSWindow*) info.nswindow retain];
@@ -693,6 +766,8 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
: processEventsFlags(0),
runLoopTimerRef(0),
blockSendPostedEvents(false),
+ currentExecIsNSAppRun(false),
+ nsAppRunCalledByQt(false),
cleanupModalSessionsNeeded(false),
currentModalSessionCached(0),
lastSerial(-1),
@@ -783,8 +858,19 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
if (cleanupModalSessionsNeeded)
cleanupModalSessions();
- if (interrupt)
+ 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();
+ }
return;
+ }
int serial = serialNumber.load();
if (!threadData->canWait || (serial != lastSerial)) {
@@ -805,6 +891,11 @@ void QCocoaEventDispatcherPrivate::firstLoopEntry(CFRunLoopObserverRef ref,
void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info)
{
QCocoaEventDispatcherPrivate *d = static_cast<QCocoaEventDispatcherPrivate *>(info);
+ if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) {
+ // processEvents() was called "manually," ignore this source for now
+ d->maybeCancelWaitForMoreEvents();
+ return;
+ }
d->processPostedEvents();
d->maybeCancelWaitForMoreEvents();
}
diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
index 5bd0ad2a43..91fb52eb6d 100644
--- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
@@ -203,10 +203,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
- (void)closePanel
{
- if (mDialogIsExecuting) {
- mDialogIsExecuting = false;
- [NSApp stopModal];
- }
[mFontPanel close];
}
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index ef242195c0..6d1882f622 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 = NSApp;
+ NSApplication *cocoaApplication = [QNSApplication sharedApplication];
qt_redirectNSApplicationSendEvent();
if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
@@ -280,8 +280,9 @@ 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:[delegate reflectionDelegate]];
+ [[NSApplication sharedApplication] setDelegate: 0];
}
// 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 654ed68e26..806effc929 100644
--- a/src/plugins/platforms/cocoa/qcocoaintrospection.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
@@ -79,33 +79,43 @@ QT_BEGIN_NAMESPACE
void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel, SEL backupSel)
{
- // 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;
+#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;
- 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)
{
- Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
- Method backupMethodInBaseClass = class_getInstanceMethod(baseClass, backupSel);
- method_setImplementation(originalMethod, method_getImplementation(backupMethodInBaseClass));
+#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));
+ }
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamain.mm b/src/plugins/platforms/cocoa/qcocoamain.mm
deleted file mode 100644
index 51d27e0c72..0000000000
--- a/src/plugins/platforms/cocoa/qcocoamain.mm
+++ /dev/null
@@ -1,181 +0,0 @@
-/****************************************************************************
-**
-** 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);
-}