diff options
author | Richard Moe Gustavsen <richard.gustavsen@nokia.com> | 2010-01-08 14:32:01 (GMT) |
---|---|---|
committer | Richard Moe Gustavsen <richard.gustavsen@nokia.com> | 2010-01-12 12:49:54 (GMT) |
commit | aca933dea3858c0b6db4a02063583da24e80b6c3 (patch) | |
tree | b60880ba7c6e0bbb4011fb19fd0be780be7aadfe /src | |
parent | ab2f88e3cfbf43afd536b9946a40e936c3dcee35 (diff) | |
download | Qt-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.
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/qcoreevent.h | 1 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_mac.mm | 21 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_p.h | 3 | ||||
-rw-r--r-- | src/gui/kernel/qcocoaapplicationdelegate_mac.mm | 7 | ||||
-rw-r--r-- | src/gui/kernel/qcocoapanel_mac.mm | 1 | ||||
-rw-r--r-- | src/gui/kernel/qcocoasharedwindowmethods_mac_p.h | 14 | ||||
-rw-r--r-- | src/gui/kernel/qcocoawindow_mac.mm | 1 | ||||
-rw-r--r-- | src/gui/kernel/qeventdispatcher_mac.mm | 3 | ||||
-rw-r--r-- | src/gui/kernel/qt_cocoa_helpers_mac.mm | 15 | ||||
-rw-r--r-- | src/gui/kernel/qt_cocoa_helpers_mac_p.h | 4 | ||||
-rw-r--r-- | src/gui/statemachine/qguistatemachine.cpp | 6 | ||||
-rw-r--r-- | src/gui/widgets/qmenu_mac.mm | 4 |
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); |