diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-04-29 14:17:08 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-04-29 14:17:09 +0200 |
commit | 85e3c53e5c5e2de993c90ece324a68d0ff62f417 (patch) | |
tree | 6f078576f01f18afcdae773e48664640ce795abe /src/plugins/platforms/cocoa | |
parent | 2e749c089f6fd93909e7cd4cc8129f2969b35185 (diff) | |
parent | 7f943968ade6a65321d4a00822f5b3a034a19e0c (diff) |
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I2a54058b64ac69c78b4120fdaf09b96e025a4c6c
Diffstat (limited to 'src/plugins/platforms/cocoa')
21 files changed, 448 insertions, 103 deletions
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 66c4e3c49c..a2fd8c0613 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -41,6 +41,8 @@ OBJECTIVE_SOURCES += main.mm \ qcocoaintrospection.mm \ qcocoakeymapper.mm \ +SOURCES += messages.cpp + HEADERS += qcocoaintegration.h \ qcocoatheme.h \ qcocoabackingstore.h \ @@ -75,6 +77,7 @@ HEADERS += qcocoaintegration.h \ qcocoasystemtrayicon.h \ qcocoaintrospection.h \ qcocoakeymapper.h \ + messages.h RESOURCES += qcocoaresources.qrc diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp new file mode 100644 index 0000000000..3db1618a50 --- /dev/null +++ b/src/plugins/platforms/cocoa/messages.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "messages.h" + +#include <QCoreApplication> + +// Translatable messages should go into this .cpp file for them to be picked up by lupdate. + +QT_BEGIN_NAMESPACE + +QString msgAboutQt() +{ + return QCoreApplication::translate("QCocoaMenuItem", "About Qt"); +} + +static const char *application_menu_strings[] = +{ + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1") +}; + +QString qt_mac_applicationmenu_string(int type) +{ + QString menuString = QString::fromLatin1(application_menu_strings[type]); + const QString translated = QCoreApplication::translate("QMenuBar", application_menu_strings[type]); + if (translated != menuString) { + return translated; + } else { + return QCoreApplication::translate("MAC_APPLICATION_MENU", application_menu_strings[type]); + } +} + +QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption) +{ + const QString aboutString = QCoreApplication::translate("QCocoaMenuItem", "About"); + if (caption.startsWith(aboutString, Qt::CaseInsensitive) || caption.endsWith(aboutString, Qt::CaseInsensitive)) + return QPlatformMenuItem::AboutRole; + if (caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Config"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Preference"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Options"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Setting"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Setup"), Qt::CaseInsensitive)) { + return QPlatformMenuItem::PreferencesRole; + } + if (caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Quit"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Exit"), Qt::CaseInsensitive)) { + return QPlatformMenuItem::QuitRole; + } + return QPlatformMenuItem::NoRole; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/messages.h b/src/plugins/platforms/cocoa/messages.h new file mode 100644 index 0000000000..09705c1e21 --- /dev/null +++ b/src/plugins/platforms/cocoa/messages.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MESSAGES_H +#define MESSAGES_H + +#include <QString> +#include <qpa/qplatformmenu.h> + +QT_BEGIN_NAMESPACE + +QString msgAboutQt(); + +QString qt_mac_applicationmenu_string(int type); + +QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption); + +QT_END_NAMESPACE + +#endif // MESSAGES_H diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 25780e79f4..9c38a874e5 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -165,8 +165,11 @@ NSString *macRole(QAccessibleInterface *interface) return roleMap[qtRole]; } - // MAC_ACCESSIBILTY_DEBUG() << "return NSAccessibilityUnknownRole"; - return NSAccessibilityUnknownRole; + // Treat unknown Qt roles as generic group container items. Returning + // NSAccessibilityUnknownRole is also possible but makes the screen + // reader focus on the item instead of passing focus to child items. + // MAC_ACCESSIBILTY_DEBUG() << "return NSAccessibilityGroupRole for unknown Qt role"; + return NSAccessibilityGroupRole; } /* diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index 12808b7041..e5b41e7a88 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -199,14 +199,14 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor) #endif const uchar *cursorData = 0; const uchar *cursorMaskData = 0; - QPoint hotspot; + QPoint hotspot = cursor->hotSpot(); switch (cursor->shape()) { case Qt::BitmapCursor: { if (cursor->pixmap().isNull()) - return createCursorFromBitmap(cursor->bitmap(), cursor->mask()); + return createCursorFromBitmap(cursor->bitmap(), cursor->mask(), hotspot); else - return createCursorFromPixmap(cursor->pixmap()); + return createCursorFromPixmap(cursor->pixmap(), hotspot); break; } case Qt::BlankCursor: { QPixmap pixmap = QPixmap(16, 16); @@ -215,19 +215,19 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor) break; } case Qt::WaitCursor: { QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/spincursor.png")); - return createCursorFromPixmap(pixmap); + return createCursorFromPixmap(pixmap, hotspot); break; } case Qt::SizeAllCursor: { QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/pluscursor.png")); - return createCursorFromPixmap(pixmap); + return createCursorFromPixmap(pixmap, hotspot); break; } case Qt::BusyCursor: { QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/waitcursor.png")); - return createCursorFromPixmap(pixmap); + return createCursorFromPixmap(pixmap, hotspot); break; } case Qt::ForbiddenCursor: { QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/forbiddencursor.png")); - return createCursorFromPixmap(pixmap); + return createCursorFromPixmap(pixmap, hotspot); break; } #define QT_USE_APPROXIMATE_CURSORS #ifdef QT_USE_APPROXIMATE_CURSORS diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 439b7f1a75..9100b9b15f 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -47,10 +47,6 @@ #include <qpa/qplatformmenu.h> #include "qcocoamenuitem.h" -@class NSMenuItem; -@class NSMenu; -@class NSObject; - QT_BEGIN_NAMESPACE class QCocoaMenu : public QPlatformMenu @@ -81,8 +77,6 @@ public: void setMinimumWidth(int width); void setFont(const QFont &font); - void setParentItem(QCocoaMenuItem* item); - inline NSMenu *nsMenu() const { return m_nativeMenu; } inline NSMenuItem *nsMenuItem() const @@ -91,6 +85,7 @@ public: virtual QPlatformMenuItem *menuItemAt(int position) const; virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const; + QList<QCocoaMenuItem *> items() const; QList<QCocoaMenuItem *> merged() const; private: QCocoaMenuItem *itemOrNull(int index) const; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index bde9ded14f..c5c5c132bc 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -45,11 +45,34 @@ #include "qcocoaautoreleasepool.h" #include <QtCore/QtDebug> +#include <QtCore/private/qthread_p.h> +#include <QtGui/private/qguiapplication_p.h> #include "qcocoaapplication.h" #include "qcocoamenuloader.h" #include "qcocoawindow.h" #import "qnsview.h" +NSString *qt_mac_removePrivateUnicode(NSString* string) +{ + int len = [string length]; + if (len) { + QVarLengthArray <unichar, 10> characters(len); + bool changed = false; + for (int i = 0; i<len; i++) { + characters[i] = [string characterAtIndex:i]; + // check if they belong to key codes in private unicode range + // currently we need to handle only the NSDeleteFunctionKey + if (characters[i] == NSDeleteFunctionKey) { + characters[i] = NSDeleteCharacter; + changed = true; + } + } + if (changed) + return [NSString stringWithCharacters:characters.data() length:len]; + } + return string; +} + static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() { return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; @@ -89,6 +112,7 @@ static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() - (void) itemFired:(NSMenuItem*) item { QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]); + QScopedLoopLevelCounter loopLevelCounter(QGuiApplicationPrivate::instance()->threadData); cocoaItem->activated(); } @@ -101,6 +125,80 @@ static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() return cocoaItem->isEnabled(); } +- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action +{ + /* + Check if the menu actually has a keysequence defined for this key event. + If it does, then we will first send the key sequence to the QWidget that has focus + since (in Qt's eyes) it needs to a chance at the key event first (QEvent::ShortcutOverride). + If the widget accepts the key event, we then return YES, but set the target and action to be nil, + which means that the action should not be triggered, and instead dispatch the event ourselves. + In every other case we return NO, which means that Cocoa can do as it pleases + (i.e., fire the menu action). + */ + + // Change the private unicode keys to the ones used in setting the "Key Equivalents" + NSString *characters = qt_mac_removePrivateUnicode([event characters]); + if ([self hasShortcut:menu + forKey:characters + // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ... + forModifiers:([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask)) + ]) { + QObject *object = qApp->focusObject(); + if (object) { + QChar ch; + int keyCode; + ulong nativeModifiers = [event modifierFlags]; + Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers]; + NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers]; + NSString *characters = [event characters]; + + if ([charactersIgnoringModifiers length] > 0) { // convert the first character into a key code + if ((modifiers & Qt::ControlModifier) && ([characters length] != 0)) { + ch = QChar([characters characterAtIndex:0]); + } else { + ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); + } + keyCode = qt_mac_cocoaKey2QtKey(ch); + } else { + // might be a dead key + ch = QChar::ReplacementCharacter; + keyCode = Qt::Key_unknown; + } + + QKeyEvent accel_ev(QEvent::ShortcutOverride, (keyCode & (~Qt::KeyboardModifierMask)), + Qt::KeyboardModifiers(keyCode & Qt::KeyboardModifierMask)); + accel_ev.ignore(); + QCoreApplication::sendEvent(object, &accel_ev); + if (accel_ev.isAccepted()) { + [[NSApp keyWindow] sendEvent: event]; + *target = nil; + *action = nil; + return YES; + } + } + } + return NO; +} + +- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier +{ + for (NSMenuItem *item in [menu itemArray]) { + if (![item isEnabled] || [item isHidden] || [item isSeparatorItem]) + continue; + if ([item hasSubmenu] + && [self hasShortcut:[item submenu] forKey:key forModifiers:modifier]) + return YES; + + NSString *menuKey = [item keyEquivalent]; + if (menuKey + && NSOrderedSame == [menuKey compare:key] + && modifier == [item keyEquivalentModifierMask]) + return YES; + } + return NO; +} + @end QT_BEGIN_NAMESPACE @@ -154,6 +252,7 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem * QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem); QCocoaMenuItem *beforeItem = static_cast<QCocoaMenuItem *>(before); + menuItem->setParent(this); cocoaItem->sync(); if (beforeItem) { int index = m_menuItems.indexOf(beforeItem); @@ -209,6 +308,10 @@ void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem) qWarning() << Q_FUNC_INFO << "Menu does not contain the item to be removed"; return; } + + if (menuItem->parent() == this) + menuItem->setParent(0); + m_menuItems.removeOne(cocoaItem); if (!cocoaItem->isMerged()) { if (m_nativeMenu != [cocoaItem->nsItem() menu]) { @@ -266,8 +369,12 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable) NSArray *itemArray = [m_nativeMenu itemArray]; for (unsigned int i = 0; i < [itemArray count]; ++i) { NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]); - if ([item isSeparatorItem]) + if ([item isSeparatorItem]) { + QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]); + if (cocoaItem) + cocoaItem->setVisible(!previousIsSeparator); [item setHidden:previousIsSeparator]; + } if (![item isHidden]) { previousItem = item; @@ -276,8 +383,12 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable) } // We now need to check the final item since we don't want any separators at the end of the list. - if (previousItem && previousIsSeparator) + if (previousItem && previousIsSeparator) { + QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([previousItem tag]); + if (cocoaItem) + cocoaItem->setVisible(false); [previousItem setHidden:YES]; + } } else { foreach (QCocoaMenuItem *item, m_menuItems) { if (!item->isSeparator()) @@ -289,11 +400,6 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable) } } -void QCocoaMenu::setParentItem(QCocoaMenuItem *item) -{ - Q_UNUSED(item); -} - void QCocoaMenu::setEnabled(bool enabled) { m_enabled = enabled; @@ -378,6 +484,11 @@ QPlatformMenuItem *QCocoaMenu::menuItemForTag(quintptr tag) const return 0; } +QList<QCocoaMenuItem *> QCocoaMenu::items() const +{ + return m_menuItems; +} + QList<QCocoaMenuItem *> QCocoaMenu::merged() const { QList<QCocoaMenuItem *> result; diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h index 2db2abcaaf..8086676cc5 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.h +++ b/src/plugins/platforms/cocoa/qcocoamenubar.h @@ -47,14 +47,13 @@ #include <qpa/qplatformmenu.h> #include "qcocoamenu.h" -@class NSMenu; - QT_BEGIN_NAMESPACE class QCocoaWindow; class QCocoaMenuBar : public QPlatformMenuBar { + Q_OBJECT public: QCocoaMenuBar(); virtual ~QCocoaMenuBar(); diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index b880db16a2..b112e40549 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -109,6 +109,8 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor [m_nativeMenu addItem: menu->nsMenuItem()]; } + platformMenu->setParent(this); + syncMenu(platformMenu); [m_nativeMenu setSubmenu: menu->nsMenu() forItem: menu->nsMenuItem()]; } @@ -123,13 +125,17 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu) } m_menus.removeOne(menu); + if (platformMenu->parent() == this) + platformMenu->setParent(0); NSUInteger realIndex = [m_nativeMenu indexOfItem:menu->nsMenuItem()]; [m_nativeMenu removeItemAtIndex: realIndex]; } void QCocoaMenuBar::syncMenu(QPlatformMenu *menu) { - Q_UNUSED(menu); + QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(menu); + Q_FOREACH (QCocoaMenuItem *item, cocoaMenu->items()) + cocoaMenu->syncMenuItem(item); } void QCocoaMenuBar::handleReparent(QWindow *newParentWindow) diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index 0e6d17343d..1e69ed5a4b 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -48,8 +48,16 @@ //#define QT_COCOA_ENABLE_MENU_DEBUG -@class NSMenuItem; -@class NSMenu; +#ifdef __OBJC__ +#define QT_FORWARD_DECLARE_OBJC_CLASS(__KLASS__) @class __KLASS__ +#else +#define QT_FORWARD_DECLARE_OBJC_CLASS(__KLASS__) typedef struct objc_object __KLASS__ +#endif + +QT_FORWARD_DECLARE_OBJC_CLASS(NSMenuItem); +QT_FORWARD_DECLARE_OBJC_CLASS(NSMenu); +QT_FORWARD_DECLARE_OBJC_CLASS(NSObject); + QT_BEGIN_NAMESPACE @@ -96,6 +104,7 @@ private: NSMenuItem *m_native; QString m_text; + bool m_textSynced; QIcon m_icon; QCocoaMenu *m_menu; bool m_isVisible; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 350ef8a16a..1255f75eb7 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -42,6 +42,8 @@ #include "qcocoamenuitem.h" #include "qcocoamenu.h" +#include "qcocoamenubar.h" +#include "messages.h" #include "qcocoahelpers.h" #include "qcocoaautoreleasepool.h" #include "qt_mac_p.h" @@ -89,6 +91,7 @@ NSUInteger keySequenceModifierMask(const QKeySequence &accel) QCocoaMenuItem::QCocoaMenuItem() : m_native(NULL), + m_textSynced(false), m_menu(NULL), m_isVisible(true), m_enabled(true), @@ -123,11 +126,13 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) { if (menu == m_menu) return; + if (m_menu && m_menu->parent() == this) + m_menu->setParent(0); QCocoaAutoReleasePool pool; m_menu = static_cast<QCocoaMenu *>(menu); if (m_menu) { - m_menu->setParentItem(this); + m_menu->setParent(this); } else { // we previously had a menu, but no longer // clear out our item so the nexy sync() call builds a new one @@ -153,6 +158,8 @@ void QCocoaMenuItem::setFont(const QFont &font) void QCocoaMenuItem::setRole(MenuRole role) { + if (role != m_role) + m_textSynced = false; // Changing role deserves a second chance. m_role = role; } @@ -190,7 +197,7 @@ NSMenuItem *QCocoaMenuItem::sync() } } - if ((m_role != NoRole) || m_merged) { + if ((m_role != NoRole && !m_textSynced) || m_merged) { NSMenuItem *mergeItem = nil; QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); switch (m_role) { @@ -210,25 +217,33 @@ NSMenuItem *QCocoaMenuItem::sync() mergeItem = [loader preferencesMenuItem]; break; case TextHeuristicRole: { - QString aboutString = tr("About").toLower(); - if (m_text.startsWith(aboutString, Qt::CaseInsensitive) - || m_text.endsWith(aboutString, Qt::CaseInsensitive)) - { + QObject *p = parent(); + int depth = 1; + QCocoaMenuBar *menubar = 0; + while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) { + ++depth; + p = p->parent(); + } + if (depth == 3 || !menubar) + break; // Menu item too deep in the hierarchy, or not connected to any menubar + + switch (detectMenuRole(m_text)) { + case QPlatformMenuItem::AboutRole: if (m_text.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1) mergeItem = [loader aboutMenuItem]; else mergeItem = [loader aboutQtMenuItem]; - } else if (m_text.startsWith(tr("Config"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Preference"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Options"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Setting"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Setup"), Qt::CaseInsensitive)) { + break; + case QPlatformMenuItem::PreferencesRole: mergeItem = [loader preferencesMenuItem]; - } else if (m_text.startsWith(tr("Quit"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Exit"), Qt::CaseInsensitive)) { + break; + case QPlatformMenuItem::QuitRole: mergeItem = [loader quitMenuItem]; + break; + default: + m_textSynced = true; + break; } - break; } @@ -237,6 +252,7 @@ NSMenuItem *QCocoaMenuItem::sync() } if (mergeItem) { + m_textSynced = true; m_merged = true; [mergeItem retain]; [m_native release]; @@ -248,6 +264,8 @@ NSMenuItem *QCocoaMenuItem::sync() m_native = nil; // create item below m_merged = false; } + } else { + m_textSynced = true; // NoRole, and that was set explicitly. So, nothing to do anymore. } if (!m_native) { @@ -257,23 +275,11 @@ NSMenuItem *QCocoaMenuItem::sync() [m_native setTag:reinterpret_cast<NSInteger>(this)]; } -// [m_native setHidden:YES]; -// [m_native setHidden:NO]; [m_native setHidden: !m_isVisible]; [m_native setEnabled: m_enabled]; - QString text = m_text; - QKeySequence accel = m_shortcut; - - { - int st = text.lastIndexOf(QLatin1Char('\t')); - if (st != -1) { - accel = QKeySequence(text.right(text.length()-(st+1))); - text.remove(st, text.length()-st); - } - } - text = mergeText(); - accel = mergeAccel(); + QString text = mergeText(); + QKeySequence accel = mergeAccel(); // Show multiple key sequences as part of the menu text. if (accel.count() > 1) @@ -323,7 +329,7 @@ QString QCocoaMenuItem::mergeText() return qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName()); } else if (m_native== [loader aboutQtMenuItem]) { if (m_text == QString("About Qt")) - return tr("About Qt"); + return msgAboutQt(); else return m_text; } else if (m_native == [loader preferencesMenuItem]) { diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index 726fe5c6d2..62b722d2d2 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -41,15 +41,18 @@ #include "qcocoamenuloader.h" +#include "messages.h" #include "qcocoahelpers.h" #include "qcocoamenubar.h" #include "qcocoamenuitem.h" #include <QtCore/private/qcore_mac_p.h> +#include <QtCore/private/qthread_p.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qdir.h> #include <QtCore/qstring.h> #include <QtCore/qdebug.h> +#include <QtGui/private/qguiapplication_p.h> QT_FORWARD_DECLARE_CLASS(QCFString) QT_FORWARD_DECLARE_CLASS(QString) @@ -57,30 +60,6 @@ QT_FORWARD_DECLARE_CLASS(QString) QT_BEGIN_NAMESPACE -#ifndef QT_NO_TRANSLATION -static const char *application_menu_strings[] = { - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1") - }; - -QString qt_mac_applicationmenu_string(int type) -{ - QString menuString = QString::fromLatin1(application_menu_strings[type]); - QString translated = qApp->translate("QMenuBar", application_menu_strings[type]); - if (translated != menuString) { - return translated; - } else { - return qApp->translate("MAC_APPLICATION_MENU", - application_menu_strings[type]); - } -} -#endif - /* Loads and instantiates the main app menu from the menu nib file(s). @@ -328,6 +307,7 @@ QT_END_NAMESPACE if ([item tag]) { QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]); + QScopedLoopLevelCounter loopLevelCounter(QGuiApplicationPrivate::instance()->threadData); cocoaItem->activated(); } } diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index ca84312059..2e5e65f577 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -65,6 +65,8 @@ public: NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; + Q_INVOKABLE void beep(); + static void *cglContextForContext(QOpenGLContext *context); static void *nsOpenGLContextForContext(QOpenGLContext* context); @@ -113,6 +115,9 @@ private: // Embedding NSViews as child QWindows static void setWindowContentView(QPlatformWindow *window, void *nsViewContentView); + // Set a QWindow as a "guest" (subwindow) of a non-QWindow + static void setEmbeddedInForeignView(QPlatformWindow *window, bool embedded); + // Register if a window should deliver touch events. Enabling // touch events has implications for delivery of other events, // for example by causing scrolling event lag. diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 84261ad273..873fa3eed9 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -120,10 +120,17 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setWindowContentView); if (resource.toLower() == "registertouchwindow") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerTouchWindow); + if (resource.toLower() == "setembeddedinforeignview") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setEmbeddedInForeignView); return 0; } +void QCocoaNativeInterface::beep() +{ + NSBeep(); +} + QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport() { #ifndef QT_NO_WIDGETS @@ -224,8 +231,17 @@ void QCocoaNativeInterface::setWindowContentView(QPlatformWindow *window, void * cocoaPlatformWindow->setContentView(reinterpret_cast<NSView *>(contentView)); } +void QCocoaNativeInterface::setEmbeddedInForeignView(QPlatformWindow *window, bool embedded) +{ + QCocoaWindow *cocoaPlatformWindow = static_cast<QCocoaWindow *>(window); + cocoaPlatformWindow->setEmbeddedInForeignView(embedded); +} + void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable) { + if (!window) + return; + // Make sure the QCocoaWindow is created when enabling. Disabling might // happen on window destruction, don't (re)create the QCocoaWindow then. if (enable) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index e1de5f0add..60f448044e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -106,6 +106,8 @@ public: void setWindowTitle(const QString &title); void setWindowFilePath(const QString &filePath); void setWindowIcon(const QIcon &icon); + void setAlertState(bool enabled); + bool isAlertState() const; void raise(); void lower(); bool isExposed() const; @@ -125,10 +127,12 @@ public: NSView *contentView() const; void setContentView(NSView *contentView); + void setEmbeddedInForeignView(bool subwindow); + void windowWillMove(); void windowDidMove(); void windowDidResize(); - void windowWillClose(); + bool windowShouldClose(); bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const; NSInteger windowLevel(Qt::WindowFlags flags); @@ -173,7 +177,10 @@ public: // for QNSView NSView *m_contentView; QNSView *m_qtView; NSWindow *m_nsWindow; - bool m_contentViewIsEmbedded; // true if the m_contentView is embedded in a "foregin" NSView hiearchy + + // TODO merge to one variable if possible + bool m_contentViewIsEmbedded; // true if the m_contentView is actually embedded in a "foreign" NSView hiearchy + bool m_contentViewIsToBeEmbedded; // true if the m_contentView is intended to be embedded in a "foreign" NSView hiearchy QNSWindowDelegate *m_nsWindowDelegate; Qt::WindowFlags m_windowFlags; @@ -190,6 +197,9 @@ public: // for QNSView bool m_frameStrutEventsEnabled; bool m_isExposed; int m_registerTouchCount; + + static const int NoAlertRequest; + NSInteger m_alertRequest; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index fc8eb0c503..5d1600dba6 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -191,10 +191,13 @@ static bool isMouseEvent(NSEvent *ev) @end +const int QCocoaWindow::NoAlertRequest = -1; + QCocoaWindow::QCocoaWindow(QWindow *tlw) : QPlatformWindow(tlw) , m_nsWindow(0) , m_contentViewIsEmbedded(false) + , m_contentViewIsToBeEmbedded(false) , m_nsWindowDelegate(0) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) @@ -205,6 +208,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_frameStrutEventsEnabled(false) , m_isExposed(false) , m_registerTouchCount(0) + , m_alertRequest(NoAlertRequest) { #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::QCocoaWindow" << this; @@ -406,7 +410,7 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; if (flags == Qt::Window) { styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask); - } else if (flags & Qt::Dialog) { + } else if ((flags & Qt::Dialog) == Qt::Dialog) { if (window()->modality() == Qt::NonModal) styleMask = NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask; else @@ -499,6 +503,21 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) } } +void QCocoaWindow::setAlertState(bool enabled) +{ + if (m_alertRequest == NoAlertRequest && enabled) { + m_alertRequest = [NSApp requestUserAttention:NSCriticalRequest]; + } else if (m_alertRequest != NoAlertRequest && !enabled) { + [NSApp cancelUserAttentionRequest:m_alertRequest]; + m_alertRequest = NoAlertRequest; + } +} + +bool QCocoaWindow::isAlertState() const +{ + return m_alertRequest != NoAlertRequest; +} + void QCocoaWindow::raise() { //qDebug() << "raise" << this; @@ -639,6 +658,12 @@ void QCocoaWindow::setContentView(NSView *contentView) recreateWindow(parent()); // Adds the content view to parent NSView } +void QCocoaWindow::setEmbeddedInForeignView(bool embedded) +{ + m_contentViewIsToBeEmbedded = embedded; + recreateWindow(0); // destroy what was already created +} + void QCocoaWindow::windowWillMove() { // Close any open popups on window move @@ -662,10 +687,12 @@ void QCocoaWindow::windowDidResize() [m_qtView updateGeometry]; } -void QCocoaWindow::windowWillClose() +bool QCocoaWindow::windowShouldClose() { - QWindowSystemInterface::handleCloseEvent(window()); + bool accepted = false; + QWindowSystemInterface::handleCloseEvent(window(), &accepted); QWindowSystemInterface::flushWindowSystemEvents(); + return accepted; } bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const @@ -700,8 +727,8 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) m_nsWindowDelegate = 0; } - if (window()->type() == Qt::SubWindow) { - // Subwindows don't have a NSWindow. + if (m_contentViewIsToBeEmbedded) { + // An embedded window doesn't have its own NSWindow. } else if (!parentWindow) { // Create a new NSWindow if this is a top-level window. m_nsWindow = createNSWindow(); @@ -866,7 +893,7 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) // if content view width or height is 0 then the window animations will crash so // do nothing except set the new state NSRect contentRect = [contentView() frame]; - if (contentRect.size.width < 0 || contentRect.size.height < 0) { + if (contentRect.size.width <= 0 || contentRect.size.height <= 0) { qWarning() << Q_FUNC_INFO << "invalid window content view size, check your window geometry"; m_synchedWindowState = newState; return; diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 68145ec914..67b16b4b32 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -107,7 +107,7 @@ QT_END_NAMESPACE - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent; - (int) convertKeyCode : (QChar)keyCode; -- (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags; ++ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags; - (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; - (void)keyDown:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 52e2d781ee..a53d6c4e44 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -172,7 +172,7 @@ static QTouchDevice *touchDevice = 0; - (void)viewDidMoveToSuperview { - if (!(m_window->type() & Qt::SubWindow)) + if (!(m_platformWindow->m_contentViewIsToBeEmbedded)) return; if ([self superview]) { @@ -208,7 +208,7 @@ static QTouchDevice *touchDevice = 0; NSRect rect = [self frame]; NSRect windowRect = [[self window] frame]; geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height); - } else if (m_window->type() & Qt::SubWindow) { + } else if (m_platformWindow->m_contentViewIsToBeEmbedded) { // embedded child window, use the frame rect ### merge with case below geometry = qt_mac_toQRect([self bounds]); } else { @@ -229,9 +229,9 @@ static QTouchDevice *touchDevice = 0; m_platformWindow->QPlatformWindow::setGeometry(geometry); // Don't send the geometry change if the QWindow is designated to be - // embedded in a foregin view hiearchy but has not actually been + // embedded in a foreign view hiearchy but has not actually been // embedded yet - it's too early. - if ((m_window->type() & Qt::SubWindow) && !m_platformWindow->m_contentViewIsEmbedded) + if (m_platformWindow->m_contentViewIsToBeEmbedded && !m_platformWindow->m_contentViewIsEmbedded) return; // Send a geometry change event to Qt, if it's ready to handle events @@ -494,7 +494,7 @@ static QTouchDevice *touchDevice = 0; QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); nativeDrag->setLastMouseEvent(theEvent, self); - Qt::KeyboardModifiers keyboardModifiers = [self convertKeyModifiers:[theEvent modifierFlags]]; + Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; QWindowSystemInterface::handleMouseEvent(m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers); } @@ -556,7 +556,7 @@ static QTouchDevice *touchDevice = 0; [inputManager handleMouseEvent:theEvent]; } } else { - if ([self convertKeyModifiers:[theEvent modifierFlags]] & Qt::MetaModifier) { + if ([QNSView convertKeyModifiers:[theEvent modifierFlags]] & Qt::MetaModifier) { m_buttons |= Qt::RightButton; m_sendUpAsRightButton = true; } else { @@ -826,7 +826,7 @@ static QTouchDevice *touchDevice = 0; if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) { NSEventPhase phase = [theEvent phase]; if (phase == NSEventPhaseBegan) { - currentWheelModifiers = [self convertKeyModifiers:[theEvent modifierFlags]]; + currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; } QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers); @@ -838,7 +838,7 @@ static QTouchDevice *touchDevice = 0; #endif { QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, - [self convertKeyModifiers:[theEvent modifierFlags]]); + [QNSView convertKeyModifiers:[theEvent modifierFlags]]); } } #endif //QT_NO_WHEELEVENT @@ -848,7 +848,7 @@ static QTouchDevice *touchDevice = 0; return qt_mac_cocoaKey2QtKey(keyChar); } -- (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags ++ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags { Qt::KeyboardModifiers qtMods =Qt::NoModifier; if (modifierFlags & NSShiftKeyMask) @@ -868,7 +868,7 @@ static QTouchDevice *touchDevice = 0; { ulong timestamp = [nsevent timestamp] * 1000; ulong nativeModifiers = [nsevent modifierFlags]; - Qt::KeyboardModifiers modifiers = [self convertKeyModifiers: nativeModifiers]; + Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers]; NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers]; NSString *characters = [nsevent characters]; @@ -948,7 +948,7 @@ static QTouchDevice *touchDevice = 0; { ulong timestamp = [nsevent timestamp] * 1000; ulong modifiers = [nsevent modifierFlags]; - Qt::KeyboardModifiers qmodifiers = [self convertKeyModifiers:modifiers]; + Qt::KeyboardModifiers qmodifiers = [QNSView convertKeyModifiers:modifiers]; // calculate the delta and remember the current modifiers for next time static ulong m_lastKnownModifiers; @@ -1278,7 +1278,7 @@ static QTouchDevice *touchDevice = 0; Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); // update these so selecting move/copy/link works - QGuiApplicationPrivate::modifier_buttons = [self convertKeyModifiers: [[NSApp currentEvent] modifierFlags]]; + QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]]; QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect()); if ([sender draggingSource] != nil) { diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index c43c0b5068..6ebb1f6ba8 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -106,9 +106,27 @@ // Hit a child, forward to child accessible interface. QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); + // FIXME: parent could be wrong QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self ]; [accessibleElement autorelease]; return [accessibleElement accessibilityHitTest:point]; } +- (id)accessibilityFocusedUIElement { + if (!m_window->accessibleRoot()) + return [super accessibilityFocusedUIElement]; + + QAccessibleInterface *childInterface = m_window->accessibleRoot()->focusChild(); + if (childInterface) { + QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); + // FIXME: parent could be wrong + QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self]; + [accessibleElement autorelease]; + return accessibleElement; + } + + // should not happen + return nil; +} + @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index 98ad7b8c9d..a5b46a971f 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -56,6 +56,7 @@ - (void)windowDidResize:(NSNotification *)notification; - (void)windowDidMove:(NSNotification *)notification; - (void)windowWillClose:(NSNotification *)notification; +- (BOOL)windowShouldClose:(NSNotification *)notification; @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index b19a401443..8e17936a78 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -80,12 +80,14 @@ } } -- (void)windowWillClose:(NSNotification *)notification +- (BOOL)windowShouldClose:(NSNotification *)notification { Q_UNUSED(notification); if (m_cocoaWindow) { - m_cocoaWindow->windowWillClose(); + return m_cocoaWindow->windowShouldClose(); } + + return YES; } @end |