summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorGabriel de Dietrich <gabriel.dedietrich@qt.io>2018-04-18 19:04:13 -0700
committerGabriel de Dietrich <gabriel.dedietrich@qt.io>2018-05-23 18:09:28 +0000
commit595c1ae9e7be14162acdfcbc573f31ef6661e718 (patch)
tree437422a3cfd7d0499510f5b375e030ee6ae4e2d2 /src/plugins/platforms
parentbd74b624d53ce076a8b6a90a66da0a19da1ec17c (diff)
Cocoa Menus: Add support for menu items in window-less apps
Since we moved the menu items validation and target/action to QNSView (thus relying on the responder chain), we need to take care of case when the applications that doesn't have any window open. By adding similar methods to QCocoaApplicationDelegate, the last responder, we ensure the menu items will be validated and will trigger properly. This is particularly necessary for dock menu items, which live separately from any top-level widget. Dock menu added to Menurama which won't quit when its last window is closed. This way we can test that dock menu items will trigger in the absence of any window. Change-Id: I56d864eb9da1f8dd5adb2a3b6c3dd5304c723117 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm67
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnsview_menus.mm16
4 files changed, 65 insertions, 30 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 3073cb6b44..0816730c54 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -90,14 +90,18 @@
#include <qglobal.h>
#include <private/qcore_mac_p.h>
-@class QT_MANGLE_NAMESPACE(QCocoaMenuLoader);
+Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaNSMenuItem));
@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate>
+@property (nonatomic, retain) NSMenu *dockMenu;
+ (instancetype)sharedDelegate;
-- (void)setDockMenu:(NSMenu *)newMenu;
- (void)setReflectionDelegate:(NSObject<NSApplicationDelegate> *)oldDelegate;
- (void)removeAppleEventHandlers;
- (bool)inLaunch;
@end
+@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) (MenuAPI)
+- (void)qt_itemFired:(QT_MANGLE_NAMESPACE(QCocoaNSMenuItem) *)item;
+@end
+
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 53407d8b62..7601fb7e17 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -73,8 +73,12 @@
#import "qcocoaapplicationdelegate.h"
-#import "qcocoamenuloader.h"
#include "qcocoaintegration.h"
+#include "qcocoamenu.h"
+#include "qcocoamenuloader.h"
+#include "qcocoamenuitem.h"
+#include "qcocoansmenu.h"
+
#include <qevent.h>
#include <qurl.h>
#include <qdebug.h>
@@ -87,7 +91,6 @@ QT_USE_NAMESPACE
@implementation QCocoaApplicationDelegate {
bool startedQuit;
- NSMenu *dockMenu;
NSObject <NSApplicationDelegate> *reflectionDelegate;
bool inLaunch;
}
@@ -129,7 +132,7 @@ QT_USE_NAMESPACE
- (void)dealloc
{
- [dockMenu release];
+ [_dockMenu release];
if (reflectionDelegate) {
[[NSApplication sharedApplication] setDelegate:reflectionDelegate];
[reflectionDelegate release];
@@ -139,20 +142,13 @@ QT_USE_NAMESPACE
[super dealloc];
}
-- (void)setDockMenu:(NSMenu*)newMenu
-{
- [newMenu retain];
- [dockMenu release];
- dockMenu = newMenu;
-}
-
- (NSMenu *)applicationDockMenu:(NSApplication *)sender
{
Q_UNUSED(sender);
// Manually invoke the delegate's -menuWillOpen: method.
// See QTBUG-39604 (and its fix) for details.
- [[dockMenu delegate] menuWillOpen:dockMenu];
- return [[dockMenu retain] autorelease];
+ [self.dockMenu.delegate menuWillOpen:self.dockMenu];
+ return [[self.dockMenu retain] autorelease];
}
- (BOOL)canQuit
@@ -444,3 +440,48 @@ QT_USE_NAMESPACE
}
@end
+
+@implementation QCocoaApplicationDelegate (Menus)
+
+- (BOOL)validateMenuItem:(NSMenuItem*)item
+{
+ auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
+ if (!nativeItem)
+ return item.enabled; // FIXME Test with with Qt as plugin or embedded QWindow.
+
+ auto *platformItem = nativeItem.platformMenuItem;
+ if (!platformItem) // Try a bit harder with orphan menu itens
+ return item.hasSubmenu || (item.enabled && (item.action != @selector(qt_itemFired:)));
+
+ // Menu-holding items are always enabled, as it's conventional in Cocoa
+ if (platformItem->menu())
+ return YES;
+
+ return platformItem->isEnabled();
+}
+
+@end
+
+@implementation QCocoaApplicationDelegate (MenuAPI)
+
+- (void)qt_itemFired:(QCocoaNSMenuItem *)item
+{
+ if (item.hasSubmenu)
+ return;
+
+ auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
+ Q_ASSERT_X(nativeItem, qPrintable(__FUNCTION__), "Triggered menu item is not a QCocoaNSMenuItem.");
+ auto *platformItem = nativeItem.platformMenuItem;
+ // Menu-holding items also get a target to play nicely
+ // with NSMenuValidation but should not trigger.
+ if (!platformItem || platformItem->menu())
+ return;
+
+ QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
+ QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
+
+ static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
+ activatedSignal.invoke(platformItem, Qt::QueuedConnection);
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
index 2a6c25ed75..3c5f4e68db 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
@@ -265,7 +265,7 @@ void QCocoaNativeInterface::setDockMenu(QPlatformMenu *platformMenu)
QMacAutoReleasePool pool;
QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu);
NSMenu *menu = cocoaPlatformMenu->nsMenu();
- [[QCocoaApplicationDelegate sharedDelegate] setDockMenu:menu];
+ [QCocoaApplicationDelegate sharedDelegate].dockMenu = menu;
}
void *QCocoaNativeInterface::qMenuToNSMenu(QPlatformMenu *platformMenu)
diff --git a/src/plugins/platforms/cocoa/qnsview_menus.mm b/src/plugins/platforms/cocoa/qnsview_menus.mm
index db3d356f2e..f0489552aa 100644
--- a/src/plugins/platforms/cocoa/qnsview_menus.mm
+++ b/src/plugins/platforms/cocoa/qnsview_menus.mm
@@ -39,6 +39,7 @@
// This file is included from qnsview.mm, and only used to organize the code
+#include <qcocoaapplicationdelegate.h>
#include <qcocoansmenu.h>
#include <qcocoamenuitem.h>
#include <qcocoamenu.h>
@@ -101,19 +102,8 @@ static bool selectorIsCutCopyPaste(SEL selector)
- (void)qt_itemFired:(QCocoaNSMenuItem *)item
{
- auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
- Q_ASSERT_X(nativeItem, qPrintable(__FUNCTION__), "Triggered menu item is not a QCocoaNSMenuItem.");
- auto *platformItem = nativeItem.platformMenuItem;
- // Menu-holding items also get a target to play nicely
- // with NSMenuValidation but should not trigger.
- if (!platformItem || platformItem->menu())
- return;
-
- QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData);
- QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]];
-
- static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
- activatedSignal.invoke(platformItem, Qt::QueuedConnection);
+ auto *appDelegate = [QCocoaApplicationDelegate sharedDelegate];
+ [appDelegate qt_itemFired:item];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector