macOS: Use NSStatusItem.menu to manage system tray menu
Using [NSStatusItem popUpStatusItemMenu:] to manually show the menu is deprecated, and was causing various issues when right clicking the menu, such as not unhighlighting the menu item when dismissing the menu, or worse, not quitting the application if a 'Quit' item was triggered from a right click. The reason we were using popUpStatusItemMenu instead of the menu property of NSStatusItem was that the latter prevented us from seeing the action message of the NSStatusItem button, which we used to emit the system tray's activated signal, but this can be solved by listing for the menu's tracking state starting. Fixes: QTBUG-103515 Pick-to: 6.4 Change-Id: I686550ebac7d94d8d11b2e3c49ed16a8240cb214 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
parent
4a5abfcea4
commit
da754d5b65
@ -45,12 +45,11 @@ public:
|
||||
bool isSystemTrayAvailable() const override;
|
||||
bool supportsMessages() const override;
|
||||
|
||||
void statusItemClicked();
|
||||
void emitActivated();
|
||||
|
||||
private:
|
||||
NSStatusItem *m_statusItem = nullptr;
|
||||
QStatusItemDelegate *m_delegate = nullptr;
|
||||
QCocoaMenu *m_menu = nullptr;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -64,6 +64,8 @@ void QCocoaSystemTrayIcon::init()
|
||||
|
||||
m_delegate = [[QStatusItemDelegate alloc] initWithSysTray:this];
|
||||
|
||||
// In case the status item does not have a menu assigned to it
|
||||
// we fall back to the item's button to detect activation.
|
||||
m_statusItem.button.target = m_delegate;
|
||||
m_statusItem.button.action = @selector(statusItemClicked);
|
||||
[m_statusItem.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown];
|
||||
@ -81,8 +83,6 @@ void QCocoaSystemTrayIcon::cleanup()
|
||||
|
||||
[m_delegate release];
|
||||
m_delegate = nil;
|
||||
|
||||
m_menu = nullptr;
|
||||
}
|
||||
|
||||
QRect QCocoaSystemTrayIcon::geometry() const
|
||||
@ -178,12 +178,20 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
|
||||
|
||||
void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu)
|
||||
{
|
||||
// We don't set the menu property of the NSStatusItem here,
|
||||
// as that would prevent us from receiving the action for the
|
||||
// click, and we wouldn't be able to emit the activated signal.
|
||||
// Instead we show the menu manually when the status item is
|
||||
// clicked.
|
||||
m_menu = static_cast<QCocoaMenu *>(menu);
|
||||
m_statusItem.menu = menu ? static_cast<QCocoaMenu *>(menu)->nsMenu() : nil;
|
||||
|
||||
if (m_statusItem.menu) {
|
||||
// When a menu is assigned, NSStatusBarButtonCell will intercept the mouse
|
||||
// down to pop up the menu, and we never see the NSStatusBarButton action.
|
||||
// To ensure we emit the 'activated' signal in both cases we detect when
|
||||
// menu starts tracking, which happens before the menu delegate is sent
|
||||
// the menuWillOpen callback we use to emit aboutToShow for the menu.
|
||||
[NSNotificationCenter.defaultCenter addObserver:m_delegate
|
||||
selector:@selector(statusItemMenuBeganTracking:)
|
||||
name:NSMenuDidBeginTrackingNotification
|
||||
object:m_statusItem.menu
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
void QCocoaSystemTrayIcon::updateToolTip(const QString &toolTip)
|
||||
@ -226,7 +234,7 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
|
||||
}
|
||||
}
|
||||
|
||||
void QCocoaSystemTrayIcon::statusItemClicked()
|
||||
void QCocoaSystemTrayIcon::emitActivated()
|
||||
{
|
||||
auto *mouseEvent = NSApp.currentEvent;
|
||||
|
||||
@ -245,9 +253,6 @@ void QCocoaSystemTrayIcon::statusItemClicked()
|
||||
}
|
||||
|
||||
emit activated(activationReason);
|
||||
|
||||
if (NSMenu *menu = m_menu ? m_menu->nsMenu() : nil)
|
||||
QT_IGNORE_DEPRECATIONS([m_statusItem popUpStatusItemMenu:menu]);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
@ -270,7 +275,12 @@ QT_END_NAMESPACE
|
||||
|
||||
- (void)statusItemClicked
|
||||
{
|
||||
self.platformSystemTray->statusItemClicked();
|
||||
self.platformSystemTray->emitActivated();
|
||||
}
|
||||
|
||||
- (void)statusItemMenuBeganTracking:(NSNotification*)notification
|
||||
{
|
||||
self.platformSystemTray->emitActivated();
|
||||
}
|
||||
|
||||
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
|
||||
|
Loading…
Reference in New Issue
Block a user