diff options
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaaccessibility.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoafiledialoghelper.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm | 88 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoakeymapper.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoakeymapper.mm | 35 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.mm | 11 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenuitem.mm | 3 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview_dragging.mm | 4 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview_menus.mm | 14 |
11 files changed, 103 insertions, 62 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 585518628d..0f5c638f7c 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -389,6 +389,8 @@ id getValueAttribute(QAccessibleInterface *interface) } if (interface->state().checkable) { + if (interface->state().checkStateMixed) + return @(2); return interface->state().checked ? @(1) : @(0); } diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h index 1d01c0d1cf..d730a063a3 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h @@ -48,6 +48,7 @@ QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSOpenSavePanelDelegate, NSObject<NSOpenSa QT_BEGIN_NAMESPACE +class QEventLoop; class QFileDialog; class QFileDialogPrivate; @@ -84,6 +85,7 @@ public: private: QNSOpenSavePanelDelegate *mDelegate; QUrl mDir; + QEventLoop *m_eventLoop = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 0909b5e21a..e0fc7dd9ce 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -179,35 +179,32 @@ static QString strippedText(QString s) - (void)closePanel { - // An already closed/closing panel has its return code set - if (mReturnCode != kReturnCodeNotSet) - return; - *mCurrentSelection = QString::fromNSString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); - if ([mSavePanel respondsToSelector:@selector(close)]) + + if (mSavePanel.sheet) + [NSApp endSheet:mSavePanel]; + else if (NSApp.modalWindow == mSavePanel) + [NSApp stopModal]; + else [mSavePanel close]; - if ([mSavePanel isSheet]) - [NSApp endSheet: mSavePanel]; } - (void)showModelessPanel { - if (mOpenPanel){ - QFileInfo info(*mCurrentSelection); - NSString *filepath = info.filePath().toNSString(); - NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()]; - bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) - || [self panel:mOpenPanel shouldEnableURL:url]; - - [self updateProperties]; - [mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""]; - - [mOpenPanel beginWithCompletionHandler:^(NSInteger result){ - mReturnCode = result; - if (mHelper) - mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSModalResponseOK); - }]; - } + QFileInfo info(*mCurrentSelection); + NSString *filepath = info.filePath().toNSString(); + NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()]; + bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) + || [self panel:mSavePanel shouldEnableURL:url]; + + [self updateProperties]; + [mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""]; + + [mSavePanel beginWithCompletionHandler:^(NSInteger result){ + mReturnCode = result; + if (mHelper) + mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSModalResponseOK); + }]; } - (BOOL)runApplicationModalPanel @@ -722,11 +719,14 @@ bool QCocoaFileDialogHelper::showCocoaFilePanel(Qt::WindowModality windowModalit createNSOpenSavePanelDelegate(); if (!mDelegate) return false; - if (windowModality == Qt::NonModal) - [mDelegate showModelessPanel]; - else if (windowModality == Qt::WindowModal && parent) + + if (windowModality == Qt::WindowModal && parent) [mDelegate showWindowModalSheet:parent]; - // no need to show a Qt::ApplicationModal dialog here, since it will be done in _q_platformRunNativeAppModalPanel() + else if (windowModality == Qt::ApplicationModal) + return true; // Defer until exec() + else + [mDelegate showModelessPanel]; + return true; } @@ -738,6 +738,10 @@ bool QCocoaFileDialogHelper::hideCocoaFilePanel() return false; } else { [mDelegate closePanel]; + + if (m_eventLoop) + m_eventLoop->exit(); + // Even when we hide it, we are still using a // native dialog, so return true: return true; @@ -746,16 +750,28 @@ bool QCocoaFileDialogHelper::hideCocoaFilePanel() void QCocoaFileDialogHelper::exec() { - // Note: If NSApp is not running (which is the case if e.g a top-most - // QEventLoop has been interrupted, and the second-most event loop has not - // yet been reactivated (regardless if [NSApp run] is still on the stack)), - // showing a native modal dialog will fail. - QMacAutoReleasePool pool; - if ([mDelegate runApplicationModalPanel]) - emit accept(); - else - emit reject(); + Q_ASSERT(mDelegate); + if (mDelegate->mSavePanel.visible) { + // WindowModal or NonModal, so already shown above + QEventLoop eventLoop; + m_eventLoop = &eventLoop; + eventLoop.exec(QEventLoop::DialogExec); + m_eventLoop = nullptr; + } else { + // ApplicationModal, so show and block using native APIs + + // Note: If NSApp is not running (which is the case if e.g a top-most + // QEventLoop has been interrupted, and the second-most event loop has not + // yet been reactivated (regardless if [NSApp run] is still on the stack)), + // showing a native modal dialog will fail. + + QMacAutoReleasePool pool; + if ([mDelegate runApplicationModalPanel]) + emit accept(); + else + emit reject(); + } } bool QCocoaFileDialogHelper::defaultNameFilterDisables() const diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/plugins/platforms/cocoa/qcocoakeymapper.h index dbf164c18e..e18c6e71fa 100644 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.h +++ b/src/plugins/platforms/cocoa/qcocoakeymapper.h @@ -75,7 +75,7 @@ private: bool updateKeyboard(); using VirtualKeyCode = unsigned short; - const KeyMap &keyMapForKey(VirtualKeyCode virtualKey, QChar unicodeKey) const; + const KeyMap &keyMapForKey(VirtualKeyCode virtualKey) const; QCFType<TISInputSourceRef> m_currentInputSource = nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm index caa68ae694..9a7b53d025 100644 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm +++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm @@ -442,7 +442,7 @@ static constexpr Qt::KeyboardModifiers modifierCombinations[] = { Returns a key map for the given \virtualKey based on all possible modifier combinations. */ -const QCocoaKeyMapper::KeyMap &QCocoaKeyMapper::keyMapForKey(VirtualKeyCode virtualKey, QChar unicodeKey) const +const QCocoaKeyMapper::KeyMap &QCocoaKeyMapper::keyMapForKey(VirtualKeyCode virtualKey) const { static_assert(sizeof(modifierCombinations) / sizeof(Qt::KeyboardModifiers) == kNumModifierCombinations); @@ -452,7 +452,7 @@ const QCocoaKeyMapper::KeyMap &QCocoaKeyMapper::keyMapForKey(VirtualKeyCode virt if (keyMap[Qt::NoModifier] != Qt::Key_unknown) return keyMap; // Already filled - qCDebug(lcQpaKeyMapper, "Updating key map for virtual key = 0x%02x!", (uint)virtualKey); + qCDebug(lcQpaKeyMapper, "Updating key map for virtual key 0x%02x", (uint)virtualKey); // Key mapping via [NSEvent charactersByApplyingModifiers:] only works for key down // events, but we might (wrongly) get into this code path for other key events such @@ -476,9 +476,10 @@ const QCocoaKeyMapper::KeyMap &QCocoaKeyMapper::keyMapForKey(VirtualKeyCode virt kUCKeyActionDown, modifierKeyState, m_keyboardKind, OptionBits(0), &m_deadKeyState, maxStringLength, &actualStringLength, unicodeString); - // Use translated unicode key if valid + // Use translated Unicode key if valid + QChar carbonUnicodeKey; if (err == noErr && actualStringLength) - unicodeKey = QChar(unicodeString[0]); + carbonUnicodeKey = QChar(unicodeString[0]); if (@available(macOS 10.15, *)) { if (canMapCocoaEvent) { @@ -487,23 +488,29 @@ const QCocoaKeyMapper::KeyMap &QCocoaKeyMapper::keyMapForKey(VirtualKeyCode virt // compare the results to Cocoa. auto cocoaModifiers = toCocoaModifiers(qtModifiers); auto *charactersWithModifiers = [NSApp.currentEvent charactersByApplyingModifiers:cocoaModifiers]; - Q_ASSERT(charactersWithModifiers && charactersWithModifiers.length > 0); - auto cocoaUnicodeKey = QChar([charactersWithModifiers characterAtIndex:0]); - if (cocoaUnicodeKey != unicodeKey) { + + QChar cocoaUnicodeKey; + if (charactersWithModifiers.length > 0) + cocoaUnicodeKey = QChar([charactersWithModifiers characterAtIndex:0]); + + if (cocoaUnicodeKey != carbonUnicodeKey) { qCWarning(lcQpaKeyMapper) << "Mismatch between Cocoa" << cocoaUnicodeKey - << "and Carbon" << unicodeKey << "for virtual key" << virtualKey + << "and Carbon" << carbonUnicodeKey << "for virtual key" << virtualKey << "with" << qtModifiers; } } } - int qtkey = toKeyCode(unicodeKey, virtualKey, qtModifiers); - if (qtkey == Qt::Key_unknown) - qtkey = unicodeKey.unicode(); + int qtKey = toKeyCode(carbonUnicodeKey, virtualKey, qtModifiers); + if (qtKey == Qt::Key_unknown) + qtKey = carbonUnicodeKey.unicode(); - keyMap[i] = qtkey; + keyMap[i] = qtKey; - qCDebug(lcQpaKeyMapper, " [%d] (%d,0x%02x,'%c')", i, qtkey, qtkey, qtkey); + qCDebug(lcQpaKeyMapper).verbosity(0) << "\t" << qtModifiers + << "+" << qUtf8Printable(QString::asprintf("0x%02x", virtualKey)) + << "=" << qUtf8Printable(QString::asprintf("%d / 0x%02x /", qtKey, qtKey)) + << QString::asprintf("%c", qtKey); } return keyMap; @@ -517,7 +524,7 @@ QList<int> QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const if (!nativeVirtualKey) return ret; - auto keyMap = keyMapForKey(nativeVirtualKey, QChar(event->key())); + auto keyMap = keyMapForKey(nativeVirtualKey); auto unmodifiedKey = keyMap[Qt::NoModifier]; Q_ASSERT(unmodifiedKey != Qt::Key_unknown); diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 1ad0cfea47..295d614ee6 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -360,6 +360,17 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, NSView *view = cocoaWindow ? cocoaWindow->view() : nil; NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil; + // store the window that this popup belongs to so that we can evaluate whether we are modally blocked + bool resetMenuParent = false; + if (!menuParent()) { + setMenuParent(cocoaWindow); + resetMenuParent = true; + } + auto menuParentGuard = qScopeGuard([&]{ + if (resetMenuParent) + setMenuParent(nullptr); + }); + QScreen *screen = nullptr; if (parentWindow) screen = parentWindow->screen(); diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 4806b244c3..0f17ec61c9 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -266,8 +266,7 @@ NSMenuItem *QCocoaMenuItem::sync() while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) { ++depth; QCocoaMenuObject *menuObject = dynamic_cast<QCocoaMenuObject *>(p); - Q_ASSERT(menuObject); - p = menuObject->menuParent(); + p = menuObject ? menuObject->menuParent() : nullptr; } if (menubar && depth < 3) diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index a975f2d76c..858039e5d5 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -102,7 +102,7 @@ void QCocoaSystemTrayIcon::init() m_statusItem.button.target = m_delegate; m_statusItem.button.action = @selector(statusItemClicked); - [m_statusItem.button sendActionOn:NSEventMaskLeftMouseUp | NSEventMaskRightMouseUp | NSEventMaskOtherMouseUp]; + [m_statusItem.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown]; } void QCocoaSystemTrayIcon::cleanup() diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index d52343f0b8..28210c83ed 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1857,7 +1857,7 @@ bool QCocoaWindow::shouldRefuseKeyWindowAndFirstResponder() // This function speaks up if there's any reason // to refuse key window or first responder state. - if (window()->flags() & Qt::WindowDoesNotAcceptFocus) + if (window()->flags() & (Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput)) return true; if (m_inSetVisible) { diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm index d4ab5f4a24..495462bf8d 100644 --- a/src/plugins/platforms/cocoa/qnsview_dragging.mm +++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm @@ -296,7 +296,9 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); Q_ASSERT(nativeDrag); nativeDrag->exitDragLoop(); - nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation)); + // for internal drag'n'drop, don't override the action the drop event accepted + if (!nativeDrag->currentDrag()) + nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation)); // Qt starts drag-and-drop on a mouse button press event. Cococa in // this case won't send the matching release event, so we have to diff --git a/src/plugins/platforms/cocoa/qnsview_menus.mm b/src/plugins/platforms/cocoa/qnsview_menus.mm index 7ae274ab04..8cfac5556a 100644 --- a/src/plugins/platforms/cocoa/qnsview_menus.mm +++ b/src/plugins/platforms/cocoa/qnsview_menus.mm @@ -73,19 +73,21 @@ static bool selectorIsCutCopyPaste(SEL selector) if (platformItem->menu()) return YES; - // Check if a modal dialog is active. Validate only menu - // items belonging to this view's window own menu bar. - if (QGuiApplication::modalWindow()) { + // Check if a modal dialog is active. If so, enable only menu + // items explicitly belonging to this window's own menu bar, or to the window. + if (QGuiApplication::modalWindow() && QGuiApplication::modalWindow()->isActive()) { QCocoaMenuBar *menubar = nullptr; + QCocoaWindow *menuWindow = nullptr; QObject *menuParent = platformItem->menuParent(); while (menuParent && !(menubar = qobject_cast<QCocoaMenuBar *>(menuParent))) { + menuWindow = qobject_cast<QCocoaWindow *>(menuParent); auto *menuObject = dynamic_cast<QCocoaMenuObject *>(menuParent); - menuParent = menuObject->menuParent(); + menuParent = menuObject ? menuObject->menuParent() : nullptr; } - // we have no menubar parent for the application menu items, e.g About and Preferences - if (!menubar || menubar->cocoaWindow() != self.platformWindow) + if ((!menuWindow || menuWindow->window() != QGuiApplication::modalWindow()) + && (!menubar || menubar->cocoaWindow() != self.platformWindow)) return NO; } |