QWidgetAction: Don't deactivate the current window on Mac

We check the name of the window class the widget's QNSView
changes window and set a flag when the that window is a native
Cocoa menu window. Later, only those views not inside a native
menu can become first responder, ensuring Qt won't deactivate
the main window.

We're allowed to reject becoming the first responder mainly
because Cocoa itself doesn't support sending key event to menu
views and, therefore, it doesn't change what's already possible.

This patch also sets the widget action visible, which needs to
be done right after reparenting it to the container widget.
Besides that, it also contains a few small code cleaning changes
related to Cocoa's support of QWidgetAction.

Change-Id: Ia2170bdc5e1f40bfa2f1091c05e9e99397c47187
Task-number: QTBUG-44015
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@theqtcompany.com>
This commit is contained in:
Gabriel de Dietrich 2015-10-22 18:36:24 +02:00
parent 07475c662e
commit b50ee28eb5
5 changed files with 16 additions and 8 deletions

View File

@ -197,6 +197,8 @@ void QCocoaMenuItem::setEnabled(bool enabled)
void QCocoaMenuItem::setNativeContents(WId item)
{
NSView *itemView = (NSView *)item;
if (m_itemView == itemView)
return;
[m_itemView release];
m_itemView = [itemView retain];
[m_itemView setAutoresizesSubviews:YES];
@ -301,8 +303,8 @@ NSMenuItem *QCocoaMenuItem::sync()
if (!m_native) {
m_native = [[NSMenuItem alloc] initWithTitle:QCFString::toNSString(m_text)
action:nil
keyEquivalent:@""];
action:nil
keyEquivalent:@""];
[m_native setTag:reinterpret_cast<NSInteger>(this)];
}

View File

@ -77,6 +77,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
bool m_scrolling;
bool m_exposedOnMoveToWindow;
NSEvent *m_currentlyInterpretedKeyEvent;
bool m_isMenuView;
}
- (id)init;

View File

@ -160,6 +160,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition | QTouchDevice::MouseEmulation);
QWindowSystemInterface::registerTouchDevice(touchDevice);
}
m_isMenuView = false;
}
return self;
}
@ -269,11 +271,11 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
- (void)viewDidMoveToWindow
{
m_isMenuView = [self.window.className isEqualToString:@"NSCarbonMenuWindow"];
if (self.window) {
// This is the case of QWidgetAction's generated QWidget inserted in an NSMenu.
// 10.9 and newer get the NSWindowDidChangeOcclusionStateNotification
if ((!_q_NSWindowDidChangeOcclusionStateNotification
&& [self.window.className isEqualToString:@"NSCarbonMenuWindow"])) {
if (!_q_NSWindowDidChangeOcclusionStateNotification && m_isMenuView) {
m_exposedOnMoveToWindow = true;
m_platformWindow->exposeWindow();
}
@ -402,7 +404,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
NSString *notificationName = [windowNotification name];
if (notificationName == NSWindowDidBecomeKeyNotification) {
if (!m_platformWindow->windowIsPopupType())
if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
QWindowSystemInterface::handleWindowActivated(m_window);
} else if (notificationName == NSWindowDidResignKeyNotification) {
// key window will be non-nil if another window became key... do not
@ -411,7 +413,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
NSWindow *keyWindow = [NSApp keyWindow];
if (!keyWindow) {
// no new key window, go ahead and set the active window to zero
if (!m_platformWindow->windowIsPopupType())
if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
QWindowSystemInterface::handleWindowActivated(0);
}
} else if (notificationName == NSWindowDidMiniaturizeNotification
@ -621,13 +623,15 @@ QT_WARNING_POP
{
if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
return NO;
if (!m_platformWindow->windowIsPopupType())
if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
QWindowSystemInterface::handleWindowActivated([self topLevelWindow]);
return YES;
}
- (BOOL)acceptsFirstResponder
{
if (m_isMenuView)
return NO;
if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder())
return NO;
if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )

View File

@ -1265,7 +1265,7 @@ void QMenuPrivate::_q_platformMenuAboutToShow()
#ifdef Q_OS_OSX
if (platformMenu)
Q_FOREACH (QAction *action, q->actions())
if (QWidget *widget = widgetItems.value(const_cast<QAction *>(action)))
if (QWidget *widget = widgetItems.value(action))
if (widget->parent() == q) {
QPlatformMenuItem *menuItem = platformMenu->menuItemForTag(reinterpret_cast<quintptr>(action));
moveWidgetToPlatformItem(widget, menuItem);

View File

@ -115,6 +115,7 @@ void QMenuPrivate::moveWidgetToPlatformItem(QWidget *widget, QPlatformMenuItem*
QObject::connect(platformMenu, SIGNAL(destroyed()), container, SLOT(deleteLater()));
container->resize(widget->sizeHint());
widget->setParent(container);
widget->setVisible(true);
NSView *containerView = container->nativeView();
QWindow *containerWindow = container->windowHandle();