summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@nokia.com>2010-01-08 14:32:01 (GMT)
committerRichard Moe Gustavsen <richard.gustavsen@nokia.com>2010-01-12 12:49:54 (GMT)
commitaca933dea3858c0b6db4a02063583da24e80b6c3 (patch)
treeb60880ba7c6e0bbb4011fb19fd0be780be7aadfe
parentab2f88e3cfbf43afd536b9946a40e936c3dcee35 (diff)
downloadQt-aca933dea3858c0b6db4a02063583da24e80b6c3.zip
Qt-aca933dea3858c0b6db4a02063583da24e80b6c3.tar.gz
Qt-aca933dea3858c0b6db4a02063583da24e80b6c3.tar.bz2
Cocoa: application will not quit when using dialogs
When creating a single dialog in the main function, and tell it to exec, we run a modal dialog. But there is really no other window on screen to be modal for. So in that case, since this is a rather common pattern for Qt applications, we allow users to quit the application from the dock. But this action is sendt as an apple event. And and that point in time, cocoa has the the apple event handler, and refuses to close down the application because it detects a modal window. Our solution is to install/overwrite the apple event handler for kAEQuit _after_ cocoa has finished its own installation. But in order to do this, we need to wait until [NSApplication run] has started, otherwise it will not take effect. And that is what this patch essentially does.
-rw-r--r--src/corelib/kernel/qcoreevent.h1
-rw-r--r--src/gui/kernel/qapplication_mac.mm21
-rw-r--r--src/gui/kernel/qapplication_p.h3
-rw-r--r--src/gui/kernel/qcocoaapplicationdelegate_mac.mm7
-rw-r--r--src/gui/kernel/qcocoapanel_mac.mm1
-rw-r--r--src/gui/kernel/qcocoasharedwindowmethods_mac_p.h14
-rw-r--r--src/gui/kernel/qcocoawindow_mac.mm1
-rw-r--r--src/gui/kernel/qeventdispatcher_mac.mm3
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac.mm15
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac_p.h4
-rw-r--r--src/gui/statemachine/qguistatemachine.cpp6
-rw-r--r--src/gui/widgets/qmenu_mac.mm4
12 files changed, 65 insertions, 15 deletions
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index 6427d17..ecca4e2 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -266,7 +266,6 @@ public:
UngrabMouse = 187,
GrabKeyboard = 188,
UngrabKeyboard = 189,
- CocoaRequestModal = 190, // Internal for requesting an application modal Cocoa Window
MacGLClearDrawable = 191, // Internal Cocoa, the window has changed, so we must clear
StateMachineSignal = 192,
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 688e51f..a815f94 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -1239,10 +1239,6 @@ void qt_init(QApplicationPrivate *priv, int)
[cocoaApp setMenu:[qtMenuLoader menu]];
[newDelegate setMenuLoader:qtMenuLoader];
[qtMenuLoader release];
-
- NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
- [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:)
- forEventClass:kInternetEventClass andEventID:kAEGetURL];
}
#endif
// Register for Carbon tablet proximity events on the event monitor target.
@@ -2435,6 +2431,23 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
#endif
}
+#ifdef QT_MAC_USE_COCOA
+void QApplicationPrivate::setupAppleEvents()
+{
+ // This function is called from the event dispatcher when NSApplication has
+ // finished initialization, which appears to be just after [NSApplication run] has
+ // started to execute. By setting up our apple events handlers this late, we override
+ // the ones set up by NSApplication.
+ QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate];
+ NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
+ [eventManager setEventHandler:newDelegate andSelector:@selector(appleEventQuit:withReplyEvent:)
+ forEventClass:kCoreEventClass andEventID:kAEQuitApplication];
+ [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:)
+ forEventClass:kInternetEventClass andEventID:kAEGetURL];
+
+}
+#endif
+
// In Carbon this is your one stop for apple events.
// In Cocoa, it ISN'T. This is the catch-all Apple Event handler that exists
// for the time between instantiating the NSApplication, but before the
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index fc9e1ab..2927c45 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -459,6 +459,9 @@ public:
static OSStatus globalEventProcessor(EventHandlerCallRef, EventRef, void *);
static OSStatus globalAppleEventProcessor(const AppleEvent *, AppleEvent *, long);
static OSStatus tabletProximityCallback(EventHandlerCallRef, EventRef, void *);
+#ifdef QT_MAC_USE_COCOA
+ static void setupAppleEvents();
+#endif
static bool qt_mac_apply_settings();
#endif
diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
index 304e5d3..fc2a5ab 100644
--- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
+++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
@@ -317,5 +317,12 @@ static void cleanupCocoaApplicationDelegate()
qt_sendSpontaneousEvent(qAppInstance(), &qtEvent);
}
+- (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
+{
+ Q_UNUSED(event);
+ Q_UNUSED(replyEvent);
+ [NSApp terminate:self];
+}
+
@end
#endif
diff --git a/src/gui/kernel/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm
index 9154284..3d9c1b9 100644
--- a/src/gui/kernel/qcocoapanel_mac.mm
+++ b/src/gui/kernel/qcocoapanel_mac.mm
@@ -46,6 +46,7 @@
#import <private/qcocoawindowdelegate_mac_p.h>
#import <private/qcocoaview_mac_p.h>
#import <private/qcocoawindowcustomthemeframe_mac_p.h>
+#import <private/qcocoaapplication_mac_p.h>
#include <QtGui/QWidget>
diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
index 31d81d9..240cfe7 100644
--- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
+++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
@@ -160,10 +160,20 @@ QT_END_NAMESPACE
qt_dispatchTabletProximityEvent(tabletEvent);
}
+- (void)qtDispatcherToQAction:(id)sender
+{
+ // If this window is modal, the menu bar will be modally shaddowed.
+ // In that case, since the window will be in the first responder chain,
+ // we can still catch the trigger here and forward it to the menu bar.
+ // This is needed as a single modal dialog on Qt should be able to access
+ // the application menu (e.g. quit).
+ [[NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)] qtDispatcherToQAction:sender];
+}
+
- (void)terminate:(id)sender
{
- // This function is called from the quit item in the
- // menubar, when this window is the first responder
+ // This function is called from the quit item in the menubar when this window
+ // is in the first responder chain (see also qtDispatcherToQAction above)
[NSApp terminate:sender];
}
diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm
index a9aa373..9250f27 100644
--- a/src/gui/kernel/qcocoawindow_mac.mm
+++ b/src/gui/kernel/qcocoawindow_mac.mm
@@ -46,6 +46,7 @@
#import <private/qcocoaview_mac_p.h>
#import <private/qt_cocoa_helpers_mac_p.h>
#import <private/qcocoawindowcustomthemeframe_mac_p.h>
+#import <private/qcocoaapplication_mac_p.h>
#include <QtGui/QWidget>
diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm
index ab1e2a1..a84eca8 100644
--- a/src/gui/kernel/qeventdispatcher_mac.mm
+++ b/src/gui/kernel/qeventdispatcher_mac.mm
@@ -1048,6 +1048,9 @@ void QEventDispatcherMacPrivate::firstLoopEntry(CFRunLoopObserverRef ref,
{
Q_UNUSED(ref);
Q_UNUSED(activity);
+#ifdef QT_MAC_USE_COCOA
+ QApplicationPrivate::setupAppleEvents();
+#endif
processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents);
}
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm
index ef680a4..41c859a 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac.mm
+++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm
@@ -1278,4 +1278,19 @@ void qt_cocoaChangeOverrideCursor(const QCursor &cursor)
}
#endif
+@implementation DebugNSApplication {
+}
+- (void)sendEvent:(NSEvent *)event
+{
+ NSLog(@"NSAppDebug: sendEvent: %@", event);
+ return [super sendEvent:event];
+}
+
+- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)sender
+{
+ NSLog(@"NSAppDebug: sendAction: %s to %@ from %@", anAction, aTarget, sender);
+ return [super sendAction:anAction to:aTarget from:sender];
+}
+@end
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
index f11ccc5..211a407 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h
+++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
@@ -181,6 +181,10 @@ inline QString qt_mac_NSStringToQString(const NSString *nsstr)
inline NSString *qt_mac_QStringToNSString(const QString &qstr)
{ return [reinterpret_cast<const NSString *>(QCFString::toCFStringRef(qstr)) autorelease]; }
+
+@interface DebugNSApplication : NSApplication {}
+@end
+
#endif
QT_END_NAMESPACE
diff --git a/src/gui/statemachine/qguistatemachine.cpp b/src/gui/statemachine/qguistatemachine.cpp
index c3a9228..aeb3dbe 100644
--- a/src/gui/statemachine/qguistatemachine.cpp
+++ b/src/gui/statemachine/qguistatemachine.cpp
@@ -469,12 +469,6 @@ static QEvent *cloneEvent(QEvent *e)
case QEvent::UngrabKeyboard:
return new QEvent(*e);
-#ifdef QT_MAC_USE_COCOA
- case QEvent::CocoaRequestModal:
- Q_ASSERT_X(false, "cloneEvent()", "not implemented");
- break;
-#endif
-
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm
index 99301ee..62a482a 100644
--- a/src/gui/widgets/qmenu_mac.mm
+++ b/src/gui/widgets/qmenu_mac.mm
@@ -625,7 +625,7 @@ static NSMenuItem *createNSMenuItem(const QString &title)
NSMenuItem *item = [[NSMenuItem alloc]
initWithTitle:qt_mac_QStringToNSString(title)
action:@selector(qtDispatcherToQAction:) keyEquivalent:@""];
- [item setTarget:getMenuLoader()];
+ [item setTarget:nil];
return item;
}
#endif
@@ -1106,7 +1106,7 @@ QMenuPrivate::QMacMenuPrivate::addAction(QMacMenuAction *action, QMacMenuAction
action->menu = merge;
[cmd retain];
[cmd setAction:@selector(qtDispatcherToQAction:)];
- [cmd setTarget:getMenuLoader()];
+ [cmd setTarget:nil];
[action->menuItem release];
action->menuItem = cmd;
QMenuMergeList *list = QMenuPrivate::mergeMenuItemsHash.value(merge);