summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm88
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.mm35
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm11
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnsview_dragging.mm4
-rw-r--r--src/plugins/platforms/cocoa/qnsview_menus.mm14
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;
}