summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2013-04-29 14:17:08 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2013-04-29 14:17:09 +0200
commit85e3c53e5c5e2de993c90ece324a68d0ff62f417 (patch)
tree6f078576f01f18afcdae773e48664640ce795abe /src/plugins/platforms/cocoa
parent2e749c089f6fd93909e7cd4cc8129f2969b35185 (diff)
parent7f943968ade6a65321d4a00822f5b3a034a19e0c (diff)
Merge remote-tracking branch 'origin/stable' into dev
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro3
-rw-r--r--src/plugins/platforms/cocoa/messages.cpp96
-rw-r--r--src/plugins/platforms/cocoa/messages.h58
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm14
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h7
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm125
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h13
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm64
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm28
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm16
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h14
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm39
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm24
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm18
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.h1
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm6
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