summaryrefslogtreecommitdiffstats
path: root/src/plugins
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
parent2e749c089f6fd93909e7cd4cc8129f2969b35185 (diff)
parent7f943968ade6a65321d4a00822f5b3a034a19e0c (diff)
Merge remote-tracking branch 'origin/stable' into dev
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/accessible/widgets/itemviews.cpp3
-rw-r--r--src/plugins/accessible/widgets/qaccessiblemenu.cpp2
-rw-r--r--src/plugins/accessible/widgets/qaccessiblemenu.h3
-rw-r--r--src/plugins/accessible/widgets/qaccessiblewidgets.cpp2
-rw-r--r--src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp3
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformintegration.cpp1
-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
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h1
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm5
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm4
-rw-r--r--src/plugins/platforms/ios/qioswindow.h6
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm6
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp27
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h20
-rw-r--r--src/plugins/platforms/windows/qtwindows_additional.h4
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp54
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp124
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h8
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp47
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h43
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp36
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp10
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp33
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h6
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp76
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h11
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp30
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h34
52 files changed, 905 insertions, 258 deletions
diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp
index 4ddd39f7ea..d460ec2c98 100644
--- a/src/plugins/accessible/widgets/itemviews.cpp
+++ b/src/plugins/accessible/widgets/itemviews.cpp
@@ -120,6 +120,8 @@ QHeaderView *QAccessibleTable::horizontalHeader() const
#ifndef QT_NO_TREEVIEW
} else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view())) {
header = tv->header();
+ if (header && header->isHidden())
+ header = 0;
#endif
}
return header;
@@ -766,7 +768,6 @@ int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const
int column = cell->m_index.column();
int index = row * view()->model()->columnCount() + column;
- Q_ASSERT(index >= treeView->model()->columnCount());
return index;
} else if (iface->role() == QAccessible::ColumnHeader){
const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.cpp b/src/plugins/accessible/widgets/qaccessiblemenu.cpp
index f248e6d05e..39ac335131 100644
--- a/src/plugins/accessible/widgets/qaccessiblemenu.cpp
+++ b/src/plugins/accessible/widgets/qaccessiblemenu.cpp
@@ -206,7 +206,7 @@ int QAccessibleMenuItem::indexOfChild(const QAccessibleInterface * child) const
bool QAccessibleMenuItem::isValid() const
{
- return m_action ? true : false;
+ return m_action && m_owner ? true : false;
}
QAccessibleInterface *QAccessibleMenuItem::parent() const
diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.h b/src/plugins/accessible/widgets/qaccessiblemenu.h
index 74d118a09e..f933a4a37e 100644
--- a/src/plugins/accessible/widgets/qaccessiblemenu.h
+++ b/src/plugins/accessible/widgets/qaccessiblemenu.h
@@ -43,6 +43,7 @@
#define QACCESSIBLEMENU_H
#include <QtWidgets/private/qaccessiblewidget_p.h>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -120,7 +121,7 @@ protected:
QAction *action() const;
private:
QAction *m_action;
- QWidget *m_owner; // can hold either QMenu or the QMenuBar that contains the action
+ QPointer<QWidget> m_owner; // can hold either QMenu or the QMenuBar that contains the action
};
#endif // QT_NO_MENU
diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp
index f20823f25b..59dc03666b 100644
--- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp
+++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp
@@ -1127,7 +1127,7 @@ QAccessibleMainWindow::QAccessibleMainWindow(QWidget *widget)
QAccessibleInterface *QAccessibleMainWindow::child(int index) const
{
QList<QWidget*> kids = childWidgets(mainWindow(), true);
- if (index < kids.count()) {
+ if (index >= 0 && index < kids.count()) {
return QAccessible::queryAccessibleInterface(kids.at(index));
}
return 0;
diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
index 1113194136..400f7aece8 100644
--- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
+++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp
@@ -280,8 +280,7 @@ ushort TableGenerator::keysymToUtf8(quint32 sym)
qDebug() << QString("keysym - 0x%1 : utf8 - %2").arg(QString::number(sym, 16))
.arg(codec->toUnicode(chars));
#endif
- const QChar *ch = QString(chars.data()).unicode();
- return ch->unicode();
+ return QString::fromUtf8(chars).at(0).unicode();
}
quint32 TableGenerator::stringToKeysym(QString keysymName)
diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
index 3de6c47ad0..f0630b5224 100644
--- a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
@@ -183,7 +183,6 @@ QAndroidPlatformIntegration::~QAndroidPlatformIntegration()
{
delete m_androidPlatformNativeInterface;
delete m_androidFDB;
- delete m_touchDevice;
QtAndroid::setAndroidPlatformIntegration(NULL);
}
QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const
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
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index 329a0a3d9b..c352e0f2d2 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -52,7 +52,6 @@ class QIOSIntegration : public QPlatformIntegration, public QPlatformNativeInter
{
public:
QIOSIntegration();
- ~QIOSIntegration();
bool hasCapability(Capability cap) const;
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index c7541c3e38..61fd1c3d60 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -79,11 +79,6 @@ QIOSIntegration::QIOSIntegration()
QWindowSystemInterface::registerTouchDevice(m_touchDevice);
}
-QIOSIntegration::~QIOSIntegration()
-{
- delete m_touchDevice;
-}
-
bool QIOSIntegration::hasCapability(Capability cap) const
{
switch (cap) {
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index 404b213966..9d3447a2e4 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -78,6 +78,10 @@
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
Q_UNUSED(duration);
+
+ if (!QCoreApplication::instance())
+ return; // FIXME: Store orientation for later (?)
+
Qt::ScreenOrientation orientation = toQtScreenOrientation(UIDeviceOrientation(toInterfaceOrientation));
if (orientation == -1)
return;
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index cefb6f9388..b86dbf7d46 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -77,6 +77,9 @@ public:
int effectiveWidth() const;
int effectiveHeight() const;
+ bool setMouseGrabEnabled(bool grab) { return grab; }
+ bool setKeyboardGrabEnabled(bool grab) { return grab; }
+
WId winId() const { return WId(m_view); };
QList<QWindowSystemInterface::TouchPoint> &touchPoints() { return m_touchPoints; }
@@ -96,6 +99,9 @@ private:
void raiseOrLower(bool raise);
void updateWindowLevel();
bool blockedByModal();
+
+ inline Qt::WindowType windowType() { return static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask)); }
+ inline bool windowIsPopup() { return windowType() & Qt::Popup & ~Qt::Window; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 5edf81af93..b173fb786f 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -475,15 +475,17 @@ void QIOSWindow::raiseOrLower(bool raise)
void QIOSWindow::updateWindowLevel()
{
- Qt::WindowType type = static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask));
+ Qt::WindowType type = windowType();
if (type == Qt::ToolTip)
m_windowLevel = 120;
else if (window()->flags() & Qt::WindowStaysOnTopHint)
m_windowLevel = 100;
else if (window()->isModal())
+ m_windowLevel = 40;
+ else if (type == Qt::Popup)
m_windowLevel = 30;
- else if (type & Qt::Popup & ~Qt::Window)
+ else if (type == Qt::SplashScreen)
m_windowLevel = 20;
else if (type == Qt::Tool)
m_windowLevel = 10;
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
index 7eb1bd30c0..ce61a8b092 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -721,22 +721,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildI
if (varChildID.vt != VT_I4)
return E_INVALIDARG;
-
- int childIndex = varChildID.lVal;
-
- QAccessibleInterface *acc = 0;
-
-
- if (childIndex == 0) {
- // Yes, some AT clients (Active Accessibility Object Inspector)
- // actually ask for the same object. As a consequence, we need to clone ourselves:
- acc = accessible;
- } else if (childIndex < 0) {
- acc = QAccessible::accessibleInterface((QAccessible::Id)childIndex);
- } else {
- acc = accessible->child(childIndex - 1);
- }
-
+ QAccessibleInterface *acc = childPointer(accessible, varChildID);
if (acc) {
*ppdispChild = QWindowsAccessibility::wrap(acc);
return S_OK;
@@ -825,7 +810,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT var
QString descr;
if (varID.lVal) {
- QAccessibleInterface *child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(accessible, varID);
if (!child)
return E_FAIL;
descr = child->text(QAccessible::Description);
@@ -850,7 +835,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelp(VARIANT varID, BST
QString help;
if (varID.lVal) {
- QAccessibleInterface *child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(accessible, varID);
if (!child)
return E_FAIL;
help = child->text(QAccessible::Help);
@@ -909,7 +894,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST
QString name;
if (varID.lVal) {
- QAccessibleInterface *child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(accessible, varID);
if (!child)
return E_FAIL;
name = child->text(QAccessible::Name);
@@ -952,7 +937,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VAR
QAccessible::Role role;
if (varID.lVal) {
- QAccessibleInterface *child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(accessible, varID);
if (!child)
return E_FAIL;
role = child->role();
@@ -987,7 +972,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VA
QAccessible::State state;
if (varID.lVal) {
- QAccessibleInterface *child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(accessible, varID);
if (!child)
return E_FAIL;
state = child->state();
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
index ef17acf3e9..d4f141c5d8 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
@@ -153,13 +153,23 @@ protected:
return 0;
}
- QAccessibleInterface *childPointer(VARIANT varID)
+ static QAccessibleInterface *childPointer(QAccessibleInterface *parent, VARIANT varID)
{
// -1 since windows API always uses 1 for the first child
- QAccessibleInterface *iface = accessibleInterface();
- if (iface)
- return accessibleInterface()->child(varID.lVal - 1);
- return 0;
+ Q_ASSERT(parent);
+
+ QAccessibleInterface *acc = 0;
+ int childIndex = varID.lVal;
+ if (childIndex == 0) {
+ // Yes, some AT clients (Active Accessibility Object Inspector)
+ // actually ask for the same object. As a consequence, we need to clone ourselves:
+ acc = parent;
+ } else if (childIndex < 0) {
+ acc = QAccessible::accessibleInterface((QAccessible::Id)childIndex);
+ } else {
+ acc = parent->child(childIndex - 1);
+ }
+ return acc;
}
private:
diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h
index 3b2e9787a2..49ddf3106b 100644
--- a/src/plugins/platforms/windows/qtwindows_additional.h
+++ b/src/plugins/platforms/windows/qtwindows_additional.h
@@ -49,6 +49,10 @@
# define WM_THEMECHANGED 0x031A
#endif
+#ifndef GWL_HWNDPARENT
+# define GWL_HWNDPARENT (-8)
+#endif
+
/* Complement the definitions and declarations missing
* when using MinGW or older Windows SDKs. */
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 3f4555a31f..872fd07729 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -842,9 +842,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::FocusOutEvent:
handleFocusEvent(et, platformWindow);
return true;
- case QtWindows::ShowEvent:
- platformWindow->handleShown();
- return false; // Indicate transient children should be shown by windows (SW_PARENTOPENING)
case QtWindows::HideEvent:
platformWindow->handleHidden();
return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING)
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 5b84725edf..33b4eb4771 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -833,6 +833,7 @@ public:
bool hideFiltersDetails() const { return m_hideFiltersDetails; }
void setHideFiltersDetails(bool h) { m_hideFiltersDetails = h; }
void setDefaultSuffix(const QString &s);
+ inline bool hasDefaultSuffix() const { return m_hasDefaultSuffix; }
inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text);
// Return the selected files for tracking in OnSelectionChanged().
@@ -857,6 +858,7 @@ public slots:
protected:
explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data);
bool init(const CLSID &clsId, const IID &iid);
+ void setDefaultSuffixSys(const QString &s);
inline IFileDialog * fileDialog() const { return m_fileDialog; }
static QString itemPath(IShellItem *item);
static QStringList libraryItemFolders(IShellItem *item);
@@ -873,12 +875,13 @@ private:
DWORD m_cookie;
QStringList m_nameFilters;
bool m_hideFiltersDetails;
+ bool m_hasDefaultSuffix;
QWindowsFileDialogSharedData m_data;
};
QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) :
m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false),
- m_data(data)
+ m_hasDefaultSuffix(false), m_data(data)
{
}
@@ -1188,6 +1191,15 @@ void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters)
void QWindowsNativeFileDialogBase::setDefaultSuffix(const QString &s)
{
+ setDefaultSuffixSys(s);
+ m_hasDefaultSuffix = !s.isEmpty();
+}
+
+void QWindowsNativeFileDialogBase::setDefaultSuffixSys(const QString &s)
+{
+ // If this parameter is non-empty, it will be appended by the dialog for the 'Any files'
+ // filter ('*'). If this parameter is non-empty and the current filter has a suffix,
+ // the dialog will append the filter's suffix.
wchar_t *wSuffix = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(s.utf16()));
m_fileDialog->SetDefaultExtension(wSuffix);
}
@@ -1321,33 +1333,45 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnFileOk(IFileDialog *)
class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase
{
+ Q_OBJECT
public:
- explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) :
- QWindowsNativeFileDialogBase(data) {}
+ explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data);
virtual QStringList selectedFiles() const;
virtual QStringList dialogResult() const;
+
+private slots:
+ void slotFilterSelected(const QString &);
};
-// Append a suffix from the name filter "Foo files (*.foo;*.bar)"
-// unless the file name already has one.
-static inline QString appendSuffix(const QString &fileName, const QString &filter)
+// Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo".
+static inline QString suffixFromFilter(const QString &filter)
{
- const int lastDot = fileName.lastIndexOf(QLatin1Char('.'));
- const int lastSlash = fileName.lastIndexOf(QLatin1Char('/'));
- if (lastDot >= 0 && (lastSlash == -1 || lastDot > lastSlash))
- return fileName;
int suffixPos = filter.indexOf(QLatin1String("(*."));
if (suffixPos < 0)
- return fileName;
+ return QString();
suffixPos += 3;
int endPos = filter.indexOf(QLatin1Char(' '), suffixPos + 1);
if (endPos < 0)
endPos = filter.indexOf(QLatin1Char(';'), suffixPos + 1);
if (endPos < 0)
endPos = filter.indexOf(QLatin1Char(')'), suffixPos + 1);
- if (endPos < 0)
- return fileName;
- return fileName + QLatin1Char('.') + filter.mid(suffixPos, endPos - suffixPos);
+ return endPos >= 0 ? filter.mid(suffixPos, endPos - suffixPos) : QString();
+}
+
+QWindowsNativeSaveFileDialog::QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data)
+ : QWindowsNativeFileDialogBase(data)
+{
+ connect(this, &QWindowsNativeFileDialogBase::filterSelected,
+ this, &QWindowsNativeSaveFileDialog::slotFilterSelected);
+}
+
+void QWindowsNativeSaveFileDialog::slotFilterSelected(const QString &filter)
+{
+ // Cause the dialog to append the suffix of the current filter unless a default
+ // suffix is set (Note: Qt 4.8 sets the selected filter's suffix before
+ // calling GetSaveFileName()).
+ if (!hasDefaultSuffix())
+ setDefaultSuffixSys(suffixFromFilter(filter));
}
QStringList QWindowsNativeSaveFileDialog::dialogResult() const
@@ -1355,7 +1379,7 @@ QStringList QWindowsNativeSaveFileDialog::dialogResult() const
QStringList result;
IShellItem *item = 0;
if (SUCCEEDED(fileDialog()->GetResult(&item)) && item)
- result.push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter()));
+ result.push_back(QWindowsNativeFileDialogBase::itemPath(item));
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 2a5e08cf41..010197d6d8 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -839,6 +839,15 @@ QWindowsWindow::~QWindowsWindow()
destroyIcon();
}
+void QWindowsWindow::fireExpose(const QRegion &region, bool force)
+{
+ if (region.isEmpty() && !force)
+ clearFlag(Exposed);
+ else
+ setFlag(Exposed);
+ QWindowSystemInterface::handleExposeEvent(window(), region);
+}
+
void QWindowsWindow::destroyWindow()
{
if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
@@ -942,13 +951,19 @@ void QWindowsWindow::setVisible(bool visible)
if (m_data.hwnd) {
if (visible) {
show_sys();
- QWindowSystemInterface::handleExposeEvent(window(),
- QRect(QPoint(), geometry().size()));
+
+ // When the window is layered, we won't get WM_PAINT, and "we" are in control
+ // over the rendering of the window
+ // There is nobody waiting for this, so we don't need to flush afterwards.
+ QWindow *w = window();
+ if (w->format().hasAlpha() || qFuzzyCompare(w->opacity(), qreal(1)))
+ fireExpose(QRect(0, 0, w->width(), w->height()));
+
} else {
if (hasMouseCapture())
setMouseGrabEnabled(false);
hide_sys();
- QWindowSystemInterface::handleExposeEvent(window(), QRegion());
+ fireExpose(QRegion());
}
}
}
@@ -998,6 +1013,24 @@ QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
return pos;
}
+// Update the transient parent for a toplevel window. The concept does not
+// really exist on Windows, the relationship is set by passing a parent along with !WS_CHILD
+// to window creation or by setting the parent using GWL_HWNDPARENT (as opposed to
+// SetParent, which would make it a real child).
+void QWindowsWindow::updateTransientParent() const
+{
+#ifndef Q_OS_WINCE
+ // Update transient parent.
+ const HWND oldTransientParent =
+ GetAncestor(m_data.hwnd, GA_PARENT) == GetDesktopWindow() ? GetAncestor(m_data.hwnd, GA_ROOTOWNER) : HWND(0);
+ HWND newTransientParent = 0;
+ if (const QWindow *tp = window()->transientParent())
+ newTransientParent = QWindowsWindow::handleOf(tp);
+ if (newTransientParent && newTransientParent != oldTransientParent)
+ SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent);
+#endif // !Q_OS_WINCE
+}
+
// partially from QWidgetPrivate::show_sys()
void QWindowsWindow::show_sys() const
{
@@ -1012,19 +1045,22 @@ void QWindowsWindow::show_sys() const
sm = SW_SHOWMINIMIZED;
if (!isVisible())
sm = SW_SHOWMINNOACTIVE;
- } else if (state & Qt::WindowMaximized) {
- sm = SW_SHOWMAXIMIZED;
- // Windows will not behave correctly when we try to maximize a window which does not
- // have minimize nor maximize buttons in the window frame. Windows would then ignore
- // non-available geometry, and rather maximize the widget to the full screen, minus the
- // window frame (caption). So, we do a trick here, by adding a maximize button before
- // maximizing the widget, and then remove the maximize button afterwards.
- if (flags & Qt::WindowTitleHint &&
- !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
- fakedMaximize = TRUE;
- setStyle(style() | WS_MAXIMIZEBOX);
- }
- }
+ } else {
+ updateTransientParent();
+ if (state & Qt::WindowMaximized) {
+ sm = SW_SHOWMAXIMIZED;
+ // Windows will not behave correctly when we try to maximize a window which does not
+ // have minimize nor maximize buttons in the window frame. Windows would then ignore
+ // non-available geometry, and rather maximize the widget to the full screen, minus the
+ // window frame (caption). So, we do a trick here, by adding a maximize button before
+ // maximizing the widget, and then remove the maximize button afterwards.
+ if (flags & Qt::WindowTitleHint &&
+ !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
+ fakedMaximize = TRUE;
+ setStyle(style() | WS_MAXIMIZEBOX);
+ }
+ } // Qt::WindowMaximized
+ } // !Qt::WindowMinimized
}
if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool)
sm = SW_SHOWNOACTIVATE;
@@ -1094,14 +1130,9 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const
}
}
-void QWindowsWindow::handleShown()
-{
- QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
-}
-
void QWindowsWindow::handleHidden()
{
- QWindowSystemInterface::handleExposeEvent(window(), QRegion());
+ fireExpose(QRegion());
}
void QWindowsWindow::setGeometry(const QRect &rectIn)
@@ -1267,28 +1298,21 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
if (message == WM_ERASEBKGND) // Backing store - ignored.
return true;
PAINTSTRUCT ps;
- if (testFlag(OpenGLSurface)) {
- // Observed painting problems with Aero style disabled (QTBUG-7865).
- if (testFlag(OpenGLDoubleBuffered))
- InvalidateRect(hwnd, 0, false);
- BeginPaint(hwnd, &ps);
- QWindowSystemInterface::handleExposeEvent(window(), QRegion(qrectFromRECT(ps.rcPaint)));
- if (!QWindowsContext::instance()->asyncExpose())
- QWindowSystemInterface::flushWindowSystemEvents();
- EndPaint(hwnd, &ps);
- } else {
- BeginPaint(hwnd, &ps);
- const QRect updateRect = qrectFromRECT(ps.rcPaint);
+ // Observed painting problems with Aero style disabled (QTBUG-7865).
+ if (testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered))
+ InvalidateRect(hwnd, 0, false);
- if (QWindowsContext::verboseIntegration)
- qDebug() << __FUNCTION__ << this << window() << updateRect;
+ BeginPaint(hwnd, &ps);
- QWindowSystemInterface::handleExposeEvent(window(), QRegion(updateRect));
- if (!QWindowsContext::instance()->asyncExpose())
- QWindowSystemInterface::flushWindowSystemEvents();
- EndPaint(hwnd, &ps);
- }
+ // If the a window is obscured by another window (such as a child window)
+ // we still need to send isExposed=true, for compatibility.
+ // Our tests depend on it.
+ fireExpose(QRegion(qrectFromRECT(ps.rcPaint)), true);
+ if (!QWindowsContext::instance()->asyncExpose())
+ QWindowSystemInterface::flushWindowSystemEvents();
+
+ EndPaint(hwnd, &ps);
return true;
}
@@ -1366,9 +1390,23 @@ void QWindowsWindow::setWindowState(Qt::WindowState state)
}
}
+// Return the effective screen for full screen mode in a virtual desktop.
+static const QScreen *effectiveScreen(const QWindow *w)
+{
+ QPoint center = w->geometry().center();
+ if (!w->isTopLevel())
+ center = w->mapToGlobal(center);
+ const QScreen *screen = w->screen();
+ if (!screen->geometry().contains(center))
+ foreach (const QScreen *sibling, screen->virtualSiblings())
+ if (sibling->geometry().contains(center))
+ return sibling;
+ return screen;
+}
+
bool QWindowsWindow::isFullScreen_sys() const
{
- return geometry_sys() == window()->screen()->geometry();
+ return geometry_sys() == effectiveScreen(window())->geometry();
}
/*!
@@ -1444,7 +1482,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
newStyle |= WS_VISIBLE;
setStyle(newStyle);
- const QRect r = window()->screen()->geometry();
+ const QRect r = effectiveScreen(window())->geometry();
const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE;
const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
setFlag(SynchronousGeometryChangeEvent);
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 2117ca50b8..6c735ede7d 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -133,7 +133,8 @@ public:
WithinSetStyle = 0x800,
WithinDestroy = 0x1000,
TouchRegistered = 0x2000,
- AlertState = 0x4000
+ AlertState = 0x4000,
+ Exposed = 0x08000
};
struct WindowData
@@ -161,7 +162,7 @@ public:
virtual void setVisible(bool visible);
bool isVisible() const;
- virtual bool isExposed() const { return m_windowState != Qt::WindowMinimized && isVisible(); }
+ virtual bool isExposed() const { return testFlag(Exposed); }
virtual bool isActive() const;
virtual bool isEmbedded(const QPlatformWindow *parentWindow) const;
virtual QPoint mapToGlobal(const QPoint &pos) const;
@@ -217,7 +218,6 @@ public:
void handleMoved();
void handleResized(int wParam);
- void handleShown();
void handleHidden();
static inline HWND handleOf(const QWindow *w);
@@ -272,12 +272,14 @@ private:
inline bool isFullScreen_sys() const;
inline void setWindowState_sys(Qt::WindowState newState);
inline void setParent_sys(const QPlatformWindow *parent) const;
+ inline void updateTransientParent() const;
void destroyWindow();
void registerDropSite();
void unregisterDropSite();
void handleGeometryChange();
void handleWindowStateChange(Qt::WindowState state);
inline void destroyIcon();
+ void fireExpose(const QRegion &region, bool force=false);
mutable WindowData m_data;
mutable unsigned m_flags;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 1504bd99d2..10a8f26614 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -242,8 +242,9 @@ void QXcbConnection::updateScreens()
((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded(screen);
}
-QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char *displayName)
+QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName)
: m_connection(0)
+ , m_canGrabServer(canGrabServer)
, m_primaryScreen(0)
, m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
, m_nativeInterface(nativeInterface)
@@ -344,6 +345,10 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char
m_drag = new QXcbDrag(this);
#endif
+ m_startupId = qgetenv("DESKTOP_STARTUP_ID");
+ if (!m_startupId.isNull())
+ qunsetenv("DESKTOP_STARTUP_ID");
+
sync();
}
@@ -386,28 +391,36 @@ QXcbConnection::~QXcbConnection()
delete m_keyboard;
}
-void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window)
+void QXcbConnection::addWindowEventListener(xcb_window_t id, QXcbWindowEventListener *eventListener)
{
- m_mapper.insert(id, window);
+ m_mapper.insert(id, eventListener);
}
-void QXcbConnection::removeWindow(xcb_window_t id)
+void QXcbConnection::removeWindowEventListener(xcb_window_t id)
{
m_mapper.remove(id);
}
-QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
+QXcbWindowEventListener *QXcbConnection::windowEventListenerFromId(xcb_window_t id)
{
return m_mapper.value(id, 0);
}
+QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
+{
+ QXcbWindowEventListener *listener = m_mapper.value(id, 0);
+ if (listener)
+ return listener->toWindow();
+ return 0;
+}
+
#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
{ \
event_t *e = (event_t *)event; \
- if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) { \
- handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
+ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \
+ handled = eventListener->handleGenericEvent(event, &result); \
if (!handled) \
- platformWindow->handler(e); \
+ eventListener->handler(e); \
} \
} \
break;
@@ -415,10 +428,10 @@ break;
#define HANDLE_KEYBOARD_EVENT(event_t, handler) \
{ \
event_t *e = (event_t *)event; \
- if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) { \
- handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
+ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \
+ handled = eventListener->handleGenericEvent(event, &result); \
if (!handled) \
- m_keyboard->handler(m_focusWindow, e); \
+ m_keyboard->handler(m_focusWindow ? m_focusWindow : eventListener, e); \
} \
} \
break;
@@ -948,6 +961,18 @@ void QXcbConnection::setFocusWindow(QXcbWindow *w)
m_focusWindow = w;
}
+void QXcbConnection::grabServer()
+{
+ if (m_canGrabServer)
+ xcb_grab_server(m_connection);
+}
+
+void QXcbConnection::ungrabServer()
+{
+ if (m_canGrabServer)
+ xcb_ungrab_server(m_connection);
+}
+
void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id)
{
xcb_client_message_event_t event;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index f69a8a9f35..44c0e28dd5 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -80,8 +80,6 @@ class QXcbClipboard;
class QXcbWMSupport;
class QXcbNativeInterface;
-typedef QHash<xcb_window_t, QXcbWindow *> WindowMapper;
-
namespace QXcbAtom {
enum Atom {
// window-manager <-> client protocols
@@ -301,12 +299,36 @@ private:
XcbPollForQueuedEventFunctionPointer m_xcb_poll_for_queued_event;
};
+class QXcbWindowEventListener
+{
+public:
+ virtual bool handleGenericEvent(xcb_generic_event_t *, long *) { return false; }
+
+ virtual void handleExposeEvent(const xcb_expose_event_t *) {}
+ virtual void handleClientMessageEvent(const xcb_client_message_event_t *) {}
+ virtual void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *) {}
+ virtual void handleMapNotifyEvent(const xcb_map_notify_event_t *) {}
+ virtual void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *) {}
+ virtual void handleButtonPressEvent(const xcb_button_press_event_t *) {}
+ virtual void handleButtonReleaseEvent(const xcb_button_release_event_t *) {}
+ virtual void handleMotionNotifyEvent(const xcb_motion_notify_event_t *) {}
+ virtual void handleEnterNotifyEvent(const xcb_enter_notify_event_t *) {}
+ virtual void handleLeaveNotifyEvent(const xcb_leave_notify_event_t *) {}
+ virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {}
+ virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {}
+ virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {}
+
+ virtual QXcbWindow *toWindow() { return 0; }
+};
+
+typedef QHash<xcb_window_t, QXcbWindowEventListener *> WindowMapper;
+
class QAbstractEventDispatcher;
class QXcbConnection : public QObject
{
Q_OBJECT
public:
- QXcbConnection(QXcbNativeInterface *nativeInterface, const char *displayName = 0);
+ QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName = 0);
~QXcbConnection();
QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); }
@@ -356,8 +378,9 @@ public:
void handleXcbError(xcb_generic_error_t *error);
void handleXcbEvent(xcb_generic_event_t *event);
- void addWindow(xcb_window_t id, QXcbWindow *window);
- void removeWindow(xcb_window_t id);
+ void addWindowEventListener(xcb_window_t id, QXcbWindowEventListener *eventListener);
+ void removeWindowEventListener(xcb_window_t id);
+ QXcbWindowEventListener *windowEventListenerFromId(xcb_window_t id);
QXcbWindow *platformWindowFromId(xcb_window_t id);
xcb_generic_event_t *checkEvent(int type);
@@ -388,6 +411,13 @@ public:
QXcbWindow *focusWindow() const { return m_focusWindow; }
void setFocusWindow(QXcbWindow *);
+ QByteArray startupId() const { return m_startupId; }
+ void clearStartupId() { m_startupId.clear(); }
+
+ void grabServer();
+ void ungrabServer();
+
+ QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; }
private slots:
void processXcbEvents();
@@ -451,6 +481,7 @@ private:
xcb_connection_t *m_connection;
const xcb_setup_t *m_setup;
+ bool m_canGrabServer;
QList<QXcbScreen *> m_screens;
int m_primaryScreen;
@@ -516,6 +547,8 @@ private:
Qt::MouseButtons m_buttons;
QXcbWindow *m_focusWindow;
+
+ QByteArray m_startupId;
};
#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index 5dbac93fde..dceac09be5 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -1160,7 +1160,7 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
if (desktop_proxy) // *WE* already have one.
return false;
- xcb_grab_server(xcb_connection());
+ connection()->grabServer();
// As per Xdnd4, use XdndProxy
xcb_window_t proxy_id = xdndProxy(connection(), w->xcb_window());
@@ -1176,7 +1176,7 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
XCB_ATOM_WINDOW, 32, 1, &proxy_id);
}
- xcb_ungrab_server(xcb_connection());
+ connection()->ungrabServer();
} else {
xdnd_widget = w;
}
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index f0cabea43d..dd1466d23c 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -91,8 +91,34 @@
#endif
#endif
+#include <QtCore/QFileInfo>
+
QT_BEGIN_NAMESPACE
+#if defined(QT_DEBUG) && defined(Q_OS_LINUX)
+// Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,.
+// or, for older Linuxes, read out 'cmdline'.
+static bool runningUnderDebugger()
+{
+ const QString parentProc = QLatin1String("/proc/") + QString::number(getppid());
+ const QFileInfo parentProcExe(parentProc + QLatin1String("/exe"));
+ if (parentProcExe.isSymLink())
+ return parentProcExe.symLinkTarget().endsWith(QLatin1String("/gdb"));
+ QFile f(parentProc + QLatin1String("/cmdline"));
+ if (!f.open(QIODevice::ReadOnly))
+ return false;
+ QByteArray s;
+ char c;
+ while (f.getChar(&c) && c) {
+ if (c == '/')
+ s.clear();
+ else
+ s += c;
+ }
+ return s == "gdb";
+}
+#endif
+
QXcbIntegration::QXcbIntegration(const QStringList &parameters)
: m_eventDispatcher(createUnixEventDispatcher())
, m_services(new QGenericUnixServices)
@@ -104,7 +130,15 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters)
#endif
m_nativeInterface.reset(new QXcbNativeInterface);
- m_connections << new QXcbConnection(m_nativeInterface.data());
+ bool canGrab = true;
+ #if defined(QT_DEBUG) && defined(Q_OS_LINUX)
+ canGrab = !runningUnderDebugger();
+ #endif
+ static bool canNotGrabEnv = qgetenv("QT_XCB_NO_GRAB_SERVER").length();
+ if (canNotGrabEnv)
+ canGrab = false;
+
+ m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab);
for (int i = 0; i < parameters.size() - 1; i += 2) {
#ifdef Q_XCB_DEBUG
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index 6db9d82cca..451dc43475 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -95,6 +95,8 @@ public:
QStringList themeNames() const;
QPlatformTheme *createPlatformTheme(const QString &name) const;
+ QXcbConnection *defaultConnection() const { return m_connections.first(); }
+
private:
QList<QXcbConnection *> m_connections;
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 02f10bba89..c66ed53152 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -1172,14 +1172,20 @@ xcb_keysym_t QXcbKeyboard::lookupString(QWindow *window, uint state, xcb_keycode
#endif
}
-void QXcbKeyboard::handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event)
+void QXcbKeyboard::handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event)
{
+ QXcbWindow *window = eventListener->toWindow();
+ if (!window)
+ return;
window->updateNetWmUserTime(event->time);
handleKeyEvent(window->window(), QEvent::KeyPress, event->detail, event->state, event->time);
}
-void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event)
+void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindowEventListener *eventListener, const xcb_key_release_event_t *event)
{
+ QXcbWindow *window = eventListener->toWindow();
+ if (!window)
+ return;
handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time);
}
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index da25c51107..3c71daa57f 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -58,8 +58,8 @@ public:
QXcbKeyboard(QXcbConnection *connection);
~QXcbKeyboard();
- void handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event);
- void handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event);
+ void handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event);
+ void handleKeyReleaseEvent(QXcbWindowEventListener *eventListener, const xcb_key_release_event_t *event);
void handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event);
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 6241898462..da60cfd2bd 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -42,6 +42,7 @@
#include "qxcbnativeinterface.h"
#include "qxcbscreen.h"
+#include "qxcbintegration.h"
#include <private/qguiapplication_p.h>
#include <QtCore/QMap>
@@ -77,6 +78,8 @@ public:
insert("glxcontext",QXcbNativeInterface::GLXContext);
insert("apptime",QXcbNativeInterface::AppTime);
insert("appusertime",QXcbNativeInterface::AppUserTime);
+ insert("hintstyle", QXcbNativeInterface::ScreenHintStyle);
+ insert("startupid", QXcbNativeInterface::StartupId);
}
};
@@ -98,6 +101,25 @@ void QXcbNativeInterface::beep() // For QApplication::beep()
#endif
}
+void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
+{
+ QByteArray lowerCaseResource = resourceString.toLower();
+ if (!qXcbResourceMap()->contains(lowerCaseResource))
+ return 0;
+
+ ResourceType resource = qXcbResourceMap()->value(lowerCaseResource);
+ void *result = 0;
+ switch (resource) {
+ case StartupId:
+ result = startupId();
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context)
{
QByteArray lowerCaseResource = resourceString.toLower();
@@ -139,6 +161,8 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resource, Q
case AppUserTime:
result = appUserTime(xcbScreen);
break;
+ case ScreenHintStyle:
+ result = reinterpret_cast<void *>(xcbScreen->hintStyle() + 1);
default:
break;
}
@@ -193,6 +217,15 @@ void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen)
return reinterpret_cast<void *>(quintptr(screen->connection()->netWmUserTime()));
}
+void *QXcbNativeInterface::startupId()
+{
+ QXcbIntegration* integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbConnection *defaultConnection = integration->defaultConnection();
+ if (defaultConnection)
+ return reinterpret_cast<void *>(const_cast<char *>(defaultConnection->startupId().constData()));
+ return 0;
+}
+
void QXcbNativeInterface::setAppTime(QScreen* screen, xcb_timestamp_t time)
{
static_cast<QXcbScreen *>(screen->handle())->connection()->setTime(time);
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index db0fa3e2ca..e27bfa5a46 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -64,11 +64,14 @@ public:
EglContext,
GLXContext,
AppTime,
- AppUserTime
+ AppUserTime,
+ ScreenHintStyle,
+ StartupId
};
QXcbNativeInterface();
+ void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE;
void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context);
void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen);
void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window);
@@ -85,6 +88,7 @@ public:
void *graphicsDeviceForWindow(QWindow *window);
void *appTime(const QXcbScreen *screen);
void *appUserTime(const QXcbScreen *screen);
+ void *startupId();
static void setAppTime(QScreen *screen, xcb_timestamp_t time);
static void setAppUserTime(QScreen *screen, xcb_timestamp_t time);
static void *eglContextForContext(QOpenGLContext *context);
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 7ae4e19dc3..a6ead49a27 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -67,6 +67,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr,
, m_number(number)
, m_refreshRate(60)
, m_forcedDpi(-1)
+ , m_hintStyle(QFontEngine::HintStyle(-1))
{
if (connection->hasXRandr())
xcb_randr_select_input(xcb_connection(), screen()->root, true);
@@ -232,6 +233,40 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const
return 0;
}
+void QXcbScreen::windowShown(QXcbWindow *window)
+{
+ // Freedesktop.org Startup Notification
+ if (!connection()->startupId().isEmpty() && window->window()->isTopLevel()) {
+ sendStartupMessage(QByteArrayLiteral("remove: ID=") + connection()->startupId());
+ connection()->clearStartupId();
+ }
+}
+
+void QXcbScreen::sendStartupMessage(const QByteArray &message) const
+{
+ xcb_window_t rootWindow = root();
+
+ xcb_client_message_event_t ev;
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 8;
+ ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO_BEGIN);
+ ev.window = rootWindow;
+ int sent = 0;
+ int length = message.length() + 1; // include NUL byte
+ const char *data = message.constData();
+ do {
+ if (sent == 20)
+ ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO);
+
+ const int start = sent;
+ const int numBytes = qMin(length - start, 20);
+ memcpy(ev.data.data8, data + start, numBytes);
+ xcb_send_event(connection()->xcb_connection(), false, rootWindow, XCB_EVENT_MASK_PROPERTY_CHANGE, (const char *) &ev);
+
+ sent += numBytes;
+ } while (sent < length);
+}
+
const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const
{
QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid);
@@ -481,6 +516,35 @@ QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height)
return result;
}
+bool QXcbScreen::xResource(const QByteArray &identifier,
+ const QByteArray &expectedIdentifier,
+ int *value)
+{
+ Q_ASSERT(value != 0);
+ if (identifier.startsWith(expectedIdentifier)) {
+ QByteArray stringValue = identifier.mid(expectedIdentifier.size());
+
+ bool ok;
+ *value = stringValue.toInt(&ok);
+ if (!ok) {
+ if (stringValue == "hintfull")
+ *value = QFontEngine::HintFull;
+ else if (stringValue == "hintnone")
+ *value = QFontEngine::HintNone;
+ else if (stringValue == "hintmedium")
+ *value = QFontEngine::HintMedium;
+ else if (stringValue == "hintslight")
+ *value = QFontEngine::HintLight;
+
+ return *value != 0;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
void QXcbScreen::readXResources()
{
int offset = 0;
@@ -508,13 +572,11 @@ void QXcbScreen::readXResources()
QList<QByteArray> split = resources.split('\n');
for (int i = 0; i < split.size(); ++i) {
const QByteArray &r = split.at(i);
- if (r.startsWith("Xft.dpi:\t")) {
- bool ok;
- int dpi = r.mid(sizeof("Xft.dpi:")).toInt(&ok);
- if (ok)
- m_forcedDpi = dpi;
- break;
- }
+ int value;
+ if (xResource(r, "Xft.dpi:\t", &value))
+ m_forcedDpi = value;
+ else if (xResource(r, "Xft.hintstyle:\t", &value))
+ m_hintStyle = QFontEngine::HintStyle(value);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 4c7d7f2c1c..0382be8a29 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -50,6 +50,8 @@
#include "qxcbobject.h"
+#include <private/qfontengine_p.h>
+
QT_BEGIN_NAMESPACE
class QXcbConnection;
@@ -85,6 +87,7 @@ public:
xcb_window_t clientLeader() const { return m_clientLeader; }
+ void windowShown(QXcbWindow *window);
QString windowManagerName() const { return m_windowManagerName; }
bool syncRequestSupported() const { return m_syncRequestSupported; }
@@ -97,7 +100,14 @@ public:
void updateRefreshRate();
void readXResources();
+
+ QFontEngine::HintStyle hintStyle() const { return m_hintStyle; }
private:
+ static bool xResource(const QByteArray &identifier,
+ const QByteArray &expectedIdentifier,
+ int *value);
+ void sendStartupMessage(const QByteArray &message) const;
+
xcb_screen_t *m_screen;
xcb_randr_crtc_t m_crtc;
QString m_outputName;
@@ -116,6 +126,7 @@ private:
QXcbCursor *m_cursor;
int m_refreshRate;
int m_forcedDpi;
+ QFontEngine::HintStyle m_hintStyle;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 68ccbfb8c0..c845b875bf 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -46,12 +46,14 @@
#include <QtGui/QIcon>
#include <QtGui/QRegion>
+#include "qxcbintegration.h"
#include "qxcbconnection.h"
#include "qxcbscreen.h"
#include "qxcbdrag.h"
#include "qxcbkeyboard.h"
#include "qxcbwmsupport.h"
#include "qxcbimage.h"
+#include "qxcbnativeinterface.h"
#include <qpa/qplatformintegration.h>
@@ -170,7 +172,9 @@ static inline QImage::Format imageFormatForDepth(int depth)
case 32: return QImage::Format_ARGB32_Premultiplied;
case 24: return QImage::Format_RGB32;
case 16: return QImage::Format_RGB16;
- default: return QImage::Format_Invalid;
+ default:
+ qWarning("Unsupported screen depth: %d", depth);
+ return QImage::Format_Invalid;
}
}
@@ -221,7 +225,7 @@ void QXcbWindow::create()
m_window = m_screen->root();
m_depth = m_screen->screen()->root_depth;
m_imageFormat = imageFormatForDepth(m_depth);
- connection()->addWindow(m_window, this);
+ connection()->addWindowEventListener(m_window, this);
return;
}
@@ -344,7 +348,7 @@ void QXcbWindow::create()
0)); // value list
}
- connection()->addWindow(m_window, this);
+ connection()->addWindowEventListener(m_window, this);
Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values));
@@ -478,7 +482,7 @@ void QXcbWindow::destroy()
xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
m_netWmUserTimeWindow = XCB_NONE;
}
- connection()->removeWindow(m_window);
+ connection()->removeWindowEventListener(m_window);
Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
m_window = 0;
}
@@ -651,6 +655,9 @@ void QXcbWindow::show()
updateNetWmUserTime(connection()->time());
Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
+
+ m_screen->windowShown(this);
+
xcb_flush(xcb_connection());
connection()->sync();
@@ -1441,6 +1448,14 @@ private:
bool m_pending;
};
+bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result)
+{
+ return QWindowSystemInterface::handleNativeEvent(window(),
+ connection()->nativeInterface()->genericEventFilterType(),
+ event,
+ result);
+}
+
void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
{
QRect rect(event->x, event->y, event->width, event->height);
@@ -1486,6 +1501,11 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
connection()->setTime(event->data.data32[1]);
m_syncValue.lo = event->data.data32[2];
m_syncValue.hi = event->data.data32[3];
+#ifndef QT_NO_WHATSTHIS
+ } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) {
+ QEvent *e = new QEvent(QEvent::EnterWhatsThisMode);
+ QGuiApplication::postEvent(QGuiApplication::instance(), e);
+#endif
} else {
qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]);
}
@@ -1671,6 +1691,8 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
handleMouseEvent(event->time, local, global, modifiers);
}
+QXcbWindow *QXcbWindow::toWindow() { return this; }
+
void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers)
{
connection()->setTime(time);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 300596845e..5601a115e9 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
class QXcbScreen;
class QXcbEGLSurface;
class QIcon;
-class QXcbWindow : public QXcbObject, public QPlatformWindow
+class QXcbWindow : public QXcbObject, public QXcbWindowEventListener, public QPlatformWindow
{
public:
enum NetWmState {
@@ -126,20 +126,24 @@ public:
uint depth() const { return m_depth; }
QImage::Format imageFormat() const { return m_imageFormat; }
- void handleExposeEvent(const xcb_expose_event_t *event);
- void handleClientMessageEvent(const xcb_client_message_event_t *event);
- void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event);
- void handleMapNotifyEvent(const xcb_map_notify_event_t *event);
- void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event);
- void handleButtonPressEvent(const xcb_button_press_event_t *event);
- void handleButtonReleaseEvent(const xcb_button_release_event_t *event);
- void handleMotionNotifyEvent(const xcb_motion_notify_event_t *event);
-
- void handleEnterNotifyEvent(const xcb_enter_notify_event_t *event);
- void handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event);
- void handleFocusInEvent(const xcb_focus_in_event_t *event);
- void handleFocusOutEvent(const xcb_focus_out_event_t *event);
- void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event);
+ bool handleGenericEvent(xcb_generic_event_t *event, long *result) Q_DECL_OVERRIDE;
+
+ void handleExposeEvent(const xcb_expose_event_t *event) Q_DECL_OVERRIDE;
+ void handleClientMessageEvent(const xcb_client_message_event_t *event) Q_DECL_OVERRIDE;
+ void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event) Q_DECL_OVERRIDE;
+ void handleMapNotifyEvent(const xcb_map_notify_event_t *event) Q_DECL_OVERRIDE;
+ void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) Q_DECL_OVERRIDE;
+ void handleButtonPressEvent(const xcb_button_press_event_t *event) Q_DECL_OVERRIDE;
+ void handleButtonReleaseEvent(const xcb_button_release_event_t *event) Q_DECL_OVERRIDE;
+ void handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) Q_DECL_OVERRIDE;
+
+ void handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) Q_DECL_OVERRIDE;
+ void handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) Q_DECL_OVERRIDE;
+ void handleFocusInEvent(const xcb_focus_in_event_t *event) Q_DECL_OVERRIDE;
+ void handleFocusOutEvent(const xcb_focus_out_event_t *event) Q_DECL_OVERRIDE;
+ void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) Q_DECL_OVERRIDE;
+
+ QXcbWindow *toWindow() Q_DECL_OVERRIDE;
void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers);