diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-03-28 12:33:32 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-03-28 12:33:32 +0100 |
commit | ad809526d63b2c6a1dd94282fa0a807f72ee580d (patch) | |
tree | 05501efa0dae0b4b8cf72d254efbbbab2ad3cb2d /src/plugins | |
parent | 9149f31aeaf3fce0c5ba5c20da0b9f2b56368abb (diff) | |
parent | c7cca2dd74bcfb0a2020fbb537fd47b50b2775c0 (diff) |
Merge remote-tracking branch 'origin/stable' into dev
Conflicts:
src/plugins/platforms/qnx/qqnxtheme.cpp
src/widgets/dialogs/qfileinfogatherer.cpp
src/widgets/dialogs/qfilesystemmodel.cpp
Change-Id: Ifa536969c4beafcdfeebbf6beda1674b86750be8
Diffstat (limited to 'src/plugins')
68 files changed, 1501 insertions, 149 deletions
diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp index cb34116f32..822d9d8c77 100644 --- a/src/plugins/accessible/widgets/itemviews.cpp +++ b/src/plugins/accessible/widgets/itemviews.cpp @@ -47,7 +47,7 @@ #include <qtreeview.h> #include <private/qtreewidget_p.h> #include <QtGui/private/qaccessible2_p.h> -#include <QDebug> +#include <QtWidgets/private/qwidget_p.h> #ifndef QT_NO_ACCESSIBILITY @@ -136,6 +136,11 @@ QAccessibleTable::QAccessibleTable(QWidget *w) } } +bool QAccessibleTable::isValid() const +{ + return (view() && !qobject_cast<QWidget*>(view())->d_func()->data.in_destructor); +} + QAccessibleTable::~QAccessibleTable() { } diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h index bba698bda2..af885fe6c1 100644 --- a/src/plugins/accessible/widgets/itemviews.h +++ b/src/plugins/accessible/widgets/itemviews.h @@ -63,6 +63,7 @@ class QAccessibleTable :public QAccessibleTableInterface, public QAccessibleObje { public: explicit QAccessibleTable(QWidget *w); + bool isValid() const; virtual ~QAccessibleTable(); diff --git a/src/plugins/accessible/widgets/main.cpp b/src/plugins/accessible/widgets/main.cpp index 92cda9f3ca..ade4979256 100644 --- a/src/plugins/accessible/widgets/main.cpp +++ b/src/plugins/accessible/widgets/main.cpp @@ -172,12 +172,11 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec iface = new QAccessibleMenu(widget); #endif #ifndef QT_NO_ITEMVIEWS - } else if (classname == QLatin1String("QAbstractItemView")) { - if (qobject_cast<const QTreeView*>(widget)) { - iface = new QAccessibleTree(widget); - } else { - iface = new QAccessibleTable(widget); - } + } else if (classname == QLatin1String("QTreeView")) { + iface = new QAccessibleTree(widget); + } else if (classname == QLatin1String("QTableView") || classname == QLatin1String("QListView")) { + iface = new QAccessibleTable(widget); + // ### This should be cleaned up. We return the parent for the scrollarea to hide it. } else if (classname == QLatin1String("QWidget") && widget->objectName() == QLatin1String("qt_scrollarea_viewport") && qobject_cast<QAbstractItemView*>(widget->parentWidget())) { @@ -254,7 +253,7 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec } else if (classname == QLatin1String("QDesktopScreenWidget")) { iface = 0; - } else { + } else if (classname == QLatin1String("QWidget")) { iface = new QAccessibleWidget(widget); } diff --git a/src/plugins/accessible/widgets/widgets.json b/src/plugins/accessible/widgets/widgets.json index 094987daf5..3969fcd527 100644 --- a/src/plugins/accessible/widgets/widgets.json +++ b/src/plugins/accessible/widgets/widgets.json @@ -24,11 +24,12 @@ "QPlainTextEdit", "QMenuBar", "QMenu", - "QHeaderView", "QTabBar", "QToolBar", "QSizeGrip", - "QAbstractItemView", + "QListView", + "QTreeView", + "QTableView", "QWidget", "QSplitter", "QSplitterHandle", @@ -47,7 +48,6 @@ "QScrollArea", "QCalendarWidget", "QDockWidget", - "QAccessibleWidget", "QDesktopScreenWidget" ] } diff --git a/src/plugins/generic/generic.pro b/src/plugins/generic/generic.pro index 078db2f477..18a8295d3c 100644 --- a/src/plugins/generic/generic.pro +++ b/src/plugins/generic/generic.pro @@ -5,3 +5,7 @@ TEMPLATE = subdirs contains(QT_CONFIG, evdev) { SUBDIRS += evdevmouse evdevtouch evdevkeyboard evdevtablet } + +contains(QT_CONFIG, tslib) { + SUBDIRS += tslib +} diff --git a/src/plugins/platforminputcontexts/compose/compose.json b/src/plugins/platforminputcontexts/compose/compose.json new file mode 100644 index 0000000000..2daf89ed30 --- /dev/null +++ b/src/plugins/platforminputcontexts/compose/compose.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "compose" ] +} diff --git a/src/plugins/platforminputcontexts/compose/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro new file mode 100644 index 0000000000..6387a47a4c --- /dev/null +++ b/src/plugins/platforminputcontexts/compose/compose.pro @@ -0,0 +1,20 @@ +TARGET = composeplatforminputcontextplugin + +PLUGIN_TYPE = platforminputcontexts +PLUGIN_CLASS_NAME = QComposePlatformInputContextPlugin +load(qt_plugin) + +QT += gui-private + +LIBS += $$QMAKE_LIBS_XKBCOMMON +QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON + +SOURCES += $$PWD/main.cpp \ + $$PWD/qcomposeplatforminputcontext.cpp \ + $$PWD/generator/qtablegenerator.cpp \ + +HEADERS += $$PWD/qcomposeplatforminputcontext.h \ + $$PWD/generator/qtablegenerator.h \ + $$PWD/xkbcommon_workaround.h \ + +OTHER_FILES += $$PWD/compose.json diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp new file mode 100644 index 0000000000..5941936aec --- /dev/null +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** 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 "qtablegenerator.h" + +#include <QtCore/QRegularExpression> +#include <QtCore/QByteArray> +#include <QtCore/QTextCodec> +#include <QtCore/QDebug> +#include <QtCore/QStringList> +#include <QtCore/QString> + +#include <xkbcommon/xkbcommon.h> +#include <xkbcommon_workaround.h> + +#include <X11/keysym.h> + +//#define DEBUG_GENERATOR + +TableGenerator::TableGenerator() : m_state(NoErrors), + m_systemComposeDir(QString()) +{ + initPossibleLocations(); + findComposeFile(); + orderComposeTable(); +#ifdef DEBUG_GENERATOR + printComposeTable(); +#endif +} + +void TableGenerator::initPossibleLocations() +{ + // AFAICT there is no way to know the exact location + // of the compose files. It depends on how Xlib was configured + // on a specific platform. During the "./configure" process + // xlib generates a config.h file which contains a bunch of defines, + // including XLOCALEDIR which points to the location of the compose file dir. + // To add an extra system path use the QTCOMPOSE environment variable + if (qEnvironmentVariableIsSet("QTCOMPOSE")) { + m_possibleLocations.append(QString(qgetenv("QTCOMPOSE"))); + } + m_possibleLocations.append(QStringLiteral("/usr/share/X11/locale")); + m_possibleLocations.append(QStringLiteral("/usr/lib/X11/locale")); +} + +void TableGenerator::findComposeFile() +{ + bool found = false; + // check if XCOMPOSEFILE points to a Compose file + if (qEnvironmentVariableIsSet("XCOMPOSEFILE")) { + QString composeFile(qgetenv("XCOMPOSEFILE")); + if (composeFile.endsWith(QLatin1String("Compose"))) + found = processFile(composeFile); + else + qWarning("Qt Warning: XCOMPOSEFILE doesn't point to a valid Compose file"); +#ifdef DEBUG_GENERATOR + if (found) + qDebug() << "Using Compose file from: " << composeFile; +#endif + } + + // check if user’s home directory has a file named .XCompose + if (!found && cleanState()) { + QString composeFile = qgetenv("HOME") + QStringLiteral("/.XCompose"); + if (QFile(composeFile).exists()) + found = processFile(composeFile); +#ifdef DEBUG_GENERATOR + if (found) + qDebug() << "Using Compose file from: " << composeFile; +#endif + } + + // check for the system provided compose files + if (!found && cleanState()) { + readLocaleMappings(); + + if (cleanState()) { + + QString table = m_localeToTable.value(locale().toUpper()); + if (table.isEmpty()) + // no table mappings for the system's locale in the compose.dir + m_state = UnsupportedLocale; + else + found = processFile(systemComposeDir() + QLatin1String("/") + table); +#ifdef DEBUG_GENERATOR + if (found) + qDebug() << "Using Compose file from: " << + systemComposeDir() + QLatin1String("/") + table; +#endif + } + } + + if (found && m_composeTable.isEmpty()) + m_state = EmptyTable; + + if (!found) + m_state = MissingComposeFile; +} + +bool TableGenerator::findSystemComposeDir() +{ + bool found = false; + for (int i = 0; i < m_possibleLocations.size(); ++i) { + QString path = m_possibleLocations.at(i); + if (QFile(path + QLatin1String("/compose.dir")).exists()) { + m_systemComposeDir = path; + found = true; + break; + } + } + + if (!found) { + // should we ask to report this in the qt bug tracker? + m_state = UnknownSystemComposeDir; + qWarning("Qt Warning: Could not find a location of the system's Compose files. " + "Consider setting the QTCOMPOSE environment variable."); + } + + return found; +} + +QString TableGenerator::systemComposeDir() +{ + if (m_systemComposeDir.isNull() + && !findSystemComposeDir()) { + return QLatin1String("$QTCOMPOSE"); + } + + return m_systemComposeDir; +} + +QString TableGenerator::locale() const +{ + char *name = setlocale(LC_CTYPE, (char *)0); + return QLatin1String(name); +} + +void TableGenerator::readLocaleMappings() +{ + QFile mappings(systemComposeDir() + QLatin1String("/compose.dir")); + if (mappings.exists()) { + mappings.open(QIODevice::ReadOnly); + QTextStream in(&mappings); + // formating of compose.dir has some inconsistencies + while (!in.atEnd()) { + QString line = in.readLine(); + if (!line.startsWith("#") && line.size() != 0 && + line.at(0).isLower()) { + + QStringList pair = line.split(QRegExp(QLatin1String("\\s+"))); + QString table = pair.at(0); + if (table.endsWith(QLatin1String(":"))) + table.remove(table.size() - 1, 1); + + m_localeToTable.insert(pair.at(1).toUpper(), table); + } + } + mappings.close(); + } +} + +bool TableGenerator::processFile(QString composeFileName) +{ + QFile composeFile(composeFileName); + if (composeFile.exists()) { + composeFile.open(QIODevice::ReadOnly); + parseComposeFile(&composeFile); + return true; + } + qWarning() << QString(QLatin1String("Qt Warning: Compose file: \"%1\" can't be found")) + .arg(composeFile.fileName()); + return false; +} + +TableGenerator::~TableGenerator() +{ +} + +QList<QComposeTableElement> TableGenerator::composeTable() const +{ + return m_composeTable; +} + +void TableGenerator::parseComposeFile(QFile *composeFile) +{ +#ifdef DEBUG_GENERATOR + qDebug() << "TableGenerator::parseComposeFile: " << composeFile->fileName(); +#endif + QTextStream in(composeFile); + + while (!in.atEnd()) { + QString line = in.readLine(); + if (line.startsWith(QLatin1String("<"))) { + parseKeySequence(line); + } else if (line.startsWith(QLatin1String("include"))) { + parseIncludeInstruction(line); + } + } + + composeFile->close(); +} + +void TableGenerator::parseIncludeInstruction(QString line) +{ + // Parse something that looks like: + // include "/usr/share/X11/locale/en_US.UTF-8/Compose" + QString quote = QStringLiteral("\""); + line.remove(0, line.indexOf(quote) + 1); + line.chop(line.length() - line.indexOf(quote)); + + // expand substitutions if present + line.replace(QLatin1String("%H"), QString(qgetenv("HOME"))); + line.replace(QLatin1String("%L"), locale()); + line.replace(QLatin1String("%S"), systemComposeDir()); + + processFile(line); +} + +ushort TableGenerator::keysymToUtf8(uint32_t sym) +{ + QByteArray chars; + int bytes; + chars.resize(8); + + if (needWorkaround(sym)) { + uint32_t codepoint; + if (sym == XKB_KEY_KP_Space) + codepoint = XKB_KEY_space & 0x7f; + else + codepoint = sym & 0x7f; + + bytes = utf32_to_utf8(codepoint, chars.data()); + } else { + bytes = xkb_keysym_to_utf8(sym, chars.data(), chars.size()); + } + + if (bytes == -1) + qWarning("TableGenerator::keysymToUtf8 - buffer too small"); + + chars.resize(bytes-1); + +#ifdef DEBUG_GENERATOR + QTextCodec *codec = QTextCodec::codecForLocale(); + 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(); +} + +uint32_t TableGenerator::stringToKeysym(QString keysymName) +{ + uint32_t keysym; + const char *name = keysymName.toLatin1().constData(); + + if ((keysym = xkb_keysym_from_name(name, (xkb_keysym_flags)0)) == XKB_KEY_NoSymbol) + qWarning() << QString("Qt Warrning - invalid keysym: %1").arg(keysymName); + + return keysym; +} + +void TableGenerator::parseKeySequence(QString line) +{ + // we are interested in the lines with the following format: + // <Multi_key> <numbersign> <S> : "♬" U266c # BEAMED SIXTEENTH NOTE + int keysEnd = line.indexOf(QLatin1String(":")); + QString keys = line.left(keysEnd).trimmed(); + + // find the key sequence + QString regexp = QStringLiteral("<[^>]+>"); + QRegularExpression reg(regexp); + QRegularExpressionMatchIterator i = reg.globalMatch(keys); + QStringList keyList; + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + QString word = match.captured(0); + keyList << word; + } + + QComposeTableElement elem; + QString quote = QStringLiteral("\""); + // find the composed value - strings may be direct text encoded in the locale + // for which the compose file is to be used, or an escaped octal or hexadecimal + // character code. Octal codes are specified as "\123" and hexadecimal codes as "\0x123a". + int composeValueIndex = line.indexOf(quote, keysEnd) + 1; + const QChar valueType(line.at(composeValueIndex)); + + if (valueType == '\\' && line.at(composeValueIndex + 1).isDigit()) { + // handle octal and hex code values + QChar detectBase(line.at(composeValueIndex + 2)); + QString codeValue = line.mid(composeValueIndex + 1, line.lastIndexOf(quote) - composeValueIndex - 1); + if (detectBase == 'x') { + // hexadecimal character code + elem.value = keysymToUtf8(codeValue.toUInt(0, 16)); + } else { + // octal character code + QString hexStr = QString::number(codeValue.toUInt(0, 8), 16); + elem.value = keysymToUtf8(hexStr.toUInt(0, 16)); + } + } else { + // handle direct text encoded in the locale + elem.value = valueType.unicode(); + } + + // find the comment + int commnetIndex = line.lastIndexOf(quote) + 1; + elem.comment = line.mid(commnetIndex).trimmed(); + + // Convert to X11 keysym + int count = keyList.length(); + for (int i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { + if (i < count) { + QString keysym = keyList.at(i); + keysym.remove(keysym.length() - 1, 1); + keysym.remove(0, 1); + + if (keysym == QLatin1String("dead_inverted_breve")) + keysym = QStringLiteral("dead_invertedbreve"); + else if (keysym == QLatin1String("dead_double_grave")) + keysym = QStringLiteral("dead_doublegrave"); + + elem.keys[i] = stringToKeysym(keysym); + } else { + elem.keys[i] = 0; + } + } + m_composeTable.append(elem); +} + +void TableGenerator::printComposeTable() const +{ + if (composeTable().isEmpty()) + return; + + QString output; + QComposeTableElement elem; + QString comma = QStringLiteral(","); + int tableSize = m_composeTable.size(); + for (int i = 0; i < tableSize; ++i) { + elem = m_composeTable.at(i); + output.append(QLatin1String("{ {")); + for (int j = 0; j < QT_KEYSEQUENCE_MAX_LEN; j++) { + output.append(QString(QLatin1String("0x%1, ")).arg(QString::number(elem.keys[j],16))); + } + // take care of the trailing comma + if (i == tableSize - 1) + comma = QStringLiteral(""); + output.append(QString(QLatin1String("}, 0x%1, \"\" }%2 // %3 \n")) + .arg(QString::number(elem.value,16)) + .arg(comma) + .arg(elem.comment)); + } + + qDebug() << "output: \n" << output; +} + +void TableGenerator::orderComposeTable() +{ + // Stable-sorting to ensure that the item that appeared before the other in the + // original container will still appear first after the sort. This property is + // needed to handle the cases when user re-defines already defined key sequence + qStableSort(m_composeTable.begin(), m_composeTable.end(), Compare()); +} + diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h new file mode 100644 index 0000000000..11e7b2b422 --- /dev/null +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** 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 QTABLEGENERATOR_H +#define QTABLEGENERATOR_H + +#include <QtCore/QList> +#include <QtCore/QFile> +#include <QtCore/QMap> +#include <QtCore/QString> + +#define QT_KEYSEQUENCE_MAX_LEN 6 + +struct QComposeTableElement { + uint keys[QT_KEYSEQUENCE_MAX_LEN]; + uint value; + QString comment; +}; + +class Compare +{ +public: + bool operator () (const QComposeTableElement &lhs, const uint rhs[QT_KEYSEQUENCE_MAX_LEN]) + { + for (size_t i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { + if (lhs.keys[i] != rhs[i]) + return (lhs.keys[i] < rhs[i]); + } + return false; + } + + bool operator () (const QComposeTableElement &lhs, const QComposeTableElement &rhs) + { + for (size_t i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { + if (lhs.keys[i] != rhs.keys[i]) + return (lhs.keys[i] < rhs.keys[i]); + } + return false; + } +}; + +class TableGenerator +{ + +public: + enum TableState + { + UnsupportedLocale, + EmptyTable, + UnknownSystemComposeDir, + MissingComposeFile, + NoErrors + }; + + TableGenerator(); + ~TableGenerator(); + + void parseComposeFile(QFile *composeFile); + void printComposeTable() const; + void orderComposeTable(); + + QList<QComposeTableElement> composeTable() const; + TableState tableState() const { return m_state; } + +protected: + bool processFile(QString composeFileName); + void parseKeySequence(QString line); + void parseIncludeInstruction(QString line); + + void findComposeFile(); + bool findSystemComposeDir(); + QString systemComposeDir(); + + ushort keysymToUtf8(uint32_t sym); + uint32_t stringToKeysym(QString keysymName); + + void readLocaleMappings(); + void initPossibleLocations(); + bool cleanState() const { return ((m_state & NoErrors) == NoErrors); } + QString locale() const; + +private: + QList<QComposeTableElement> m_composeTable; + QMap<QString, QString> m_localeToTable; + TableState m_state; + QString m_systemComposeDir; + QList<QString> m_possibleLocations; +}; + +#endif // QTABLEGENERATOR_H diff --git a/src/plugins/platforminputcontexts/compose/main.cpp b/src/plugins/platforminputcontexts/compose/main.cpp new file mode 100644 index 0000000000..728c60caf5 --- /dev/null +++ b/src/plugins/platforminputcontexts/compose/main.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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 <qpa/qplatforminputcontextplugin_p.h> + +#include <QtCore/QStringList> + +#include "qcomposeplatforminputcontext.h" + +QT_BEGIN_NAMESPACE + +class QComposePlatformInputContextPlugin : public QPlatformInputContextPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface" FILE "compose.json") + +public: + QComposeInputContext *create(const QString &, const QStringList &); +}; + +QComposeInputContext *QComposePlatformInputContextPlugin::create(const QString &system, const QStringList ¶mList) +{ + Q_UNUSED(paramList); + + if (system.compare(system, QStringLiteral("compose"), Qt::CaseInsensitive) == 0) + return new QComposeInputContext; + return 0; +} + +QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp new file mode 100644 index 0000000000..433c9eec37 --- /dev/null +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp @@ -0,0 +1,268 @@ +/**************************************************************************** +** +** 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 "qcomposeplatforminputcontext.h" + +#include <QtCore/QCoreApplication> +#include <QtGui/QKeyEvent> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +//#define DEBUG_COMPOSING + +static const int ignoreKeys[] = { + Qt::Key_Shift, + Qt::Key_Control, + Qt::Key_Meta, + Qt::Key_Alt, + Qt::Key_CapsLock, + Qt::Key_Super_L, + Qt::Key_Super_R, + Qt::Key_Hyper_L, + Qt::Key_Hyper_R, + Qt::Key_Mode_switch +}; + +static const int composingKeys[] = { + Qt::Key_Multi_key, + Qt::Key_Dead_Grave, + Qt::Key_Dead_Acute, + Qt::Key_Dead_Circumflex, + Qt::Key_Dead_Tilde, + Qt::Key_Dead_Macron, + Qt::Key_Dead_Breve, + Qt::Key_Dead_Abovedot, + Qt::Key_Dead_Diaeresis, + Qt::Key_Dead_Abovering, + Qt::Key_Dead_Doubleacute, + Qt::Key_Dead_Caron, + Qt::Key_Dead_Cedilla, + Qt::Key_Dead_Ogonek, + Qt::Key_Dead_Iota, + Qt::Key_Dead_Voiced_Sound, + Qt::Key_Dead_Semivoiced_Sound, + Qt::Key_Dead_Belowdot, + Qt::Key_Dead_Hook, + Qt::Key_Dead_Horn +}; + +QComposeInputContext::QComposeInputContext() +{ + TableGenerator reader; + m_tableState = reader.tableState(); + + if ((m_tableState & TableGenerator::NoErrors) == TableGenerator::NoErrors) { + m_composeTable = reader.composeTable(); + clearComposeBuffer(); + } +} + +bool QComposeInputContext::filterEvent(const QEvent *event) +{ + // if there were errors when generating the compose table input + // context should not try to filter anything, simply return false + if ((m_tableState & TableGenerator::NoErrors) != TableGenerator::NoErrors) + return false; + + QKeyEvent *keyEvent = (QKeyEvent *)event; + // should pass only the key presses + if (keyEvent->type() != QEvent::KeyPress) { + return false; + } + + int keyval = keyEvent->key(); + int keysym = 0; + + if (ignoreKey(keyval)) + return false; + + QString text = keyEvent->text(); + if (!composeKey(keyval) && text.isEmpty()) + return false; + + keysym = keyEvent->nativeVirtualKey(); + + int nCompose = 0; + while (m_composeBuffer[nCompose] != 0 && nCompose < QT_KEYSEQUENCE_MAX_LEN) + nCompose++; + + if (nCompose == QT_KEYSEQUENCE_MAX_LEN) { + reset(); + nCompose = 0; + } + + m_composeBuffer[nCompose] = keysym; + // check sequence + if (checkComposeTable()) + return true; + + return false; +} + +bool QComposeInputContext::isValid() const +{ + return true; +} + +void QComposeInputContext::setFocusObject(QObject *object) +{ + m_focusObject = object; +} + +void QComposeInputContext::reset() +{ + clearComposeBuffer(); +} + +void QComposeInputContext::update(Qt::InputMethodQueries q) +{ + QPlatformInputContext::update(q); +} + +static bool isDuplicate(const QComposeTableElement &lhs, const QComposeTableElement &rhs) +{ + for (size_t i = 0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { + if (lhs.keys[i] != rhs.keys[i]) + return false; + } + return true; +} + +bool QComposeInputContext::checkComposeTable() +{ + QList<QComposeTableElement>::iterator it = + qLowerBound(m_composeTable.begin(), m_composeTable.end(), m_composeBuffer, Compare()); + + // prevent dereferencing an 'end' iterator, which would result in a crash + if (it == m_composeTable.end()) + it -= 1; + + QComposeTableElement elem = *it; + // would be nicer if qLowerBound had API that tells if the item was actually found + if (m_composeBuffer[0] != elem.keys[0]) { +#ifdef DEBUG_COMPOSING + qDebug( "### no match ###" ); +#endif + reset(); + return false; + } + // check if compose buffer is matched + for (int i=0; i < QT_KEYSEQUENCE_MAX_LEN; i++) { + + // check if partial match + if (m_composeBuffer[i] == 0 && elem.keys[i]) { +#ifdef DEBUG_COMPOSING + qDebug("### partial match ###"); +#endif + return true; + } + + if (m_composeBuffer[i] != elem.keys[i]) { +#ifdef DEBUG_COMPOSING + qDebug("### different entry ###"); +#endif + reset(); + return i != 0; + } + } +#ifdef DEBUG_COMPOSING + qDebug("### match exactly ###"); +#endif + + // check if the key sequence is overwriten - see the comment in + // TableGenerator::orderComposeTable() + int next = 1; + do { + // if we are at the end of the table, then we have nothing to do here + if (it + next != m_composeTable.end()) { + QComposeTableElement nextElem = *(it + next); + if (isDuplicate(elem, nextElem)) { + elem = nextElem; + next++; + continue; + } else { + break; + } + } + break; + } while (true); + + commitText(elem.value); + reset(); + + return true; +} + +void QComposeInputContext::commitText(uint character) const +{ + QInputMethodEvent event; + event.setCommitString(QChar(character)); + QCoreApplication::sendEvent(m_focusObject, &event); +} + +bool QComposeInputContext::ignoreKey(int keyval) const +{ + for (uint i = 0; i < (sizeof(ignoreKeys) / sizeof(ignoreKeys[0])); i++) + if (keyval == ignoreKeys[i]) + return true; + + return false; +} + +bool QComposeInputContext::composeKey(int keyval) const +{ + for (uint i = 0; i < (sizeof(composingKeys) / sizeof(composingKeys[0])); i++) + if (keyval == composingKeys[i]) + return true; + + return false; +} + +void QComposeInputContext::clearComposeBuffer() +{ + for (uint i=0; i < (sizeof(m_composeBuffer) / sizeof(int)); i++) + m_composeBuffer[i] = 0; +} + +QComposeInputContext::~QComposeInputContext() {} + +QT_END_NAMESPACE diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h new file mode 100644 index 0000000000..1ced2f8ded --- /dev/null +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 QCOMPOSEPLATFORMINPUTCONTEXT_H +#define QCOMPOSEPLATFORMINPUTCONTEXT_H + +#include <qpa/qplatforminputcontext.h> + +#include <QtCore/QList> + +#include "generator/qtablegenerator.h" + +QT_BEGIN_NAMESPACE + +class QEvent; + +class QComposeInputContext : public QPlatformInputContext +{ + Q_OBJECT + +public: + QComposeInputContext(); + ~QComposeInputContext(); + + bool isValid() const; + void setFocusObject(QObject *object); + void reset(); + void update(Qt::InputMethodQueries); + bool filterEvent(const QEvent *event); + +protected: + void clearComposeBuffer(); + bool ignoreKey(int keyval) const; + bool composeKey(int keyval) const; + bool checkComposeTable(); + void commitText(uint character) const; + +private: + QObject *m_focusObject; + QList<QComposeTableElement> m_composeTable; + uint m_composeBuffer[QT_KEYSEQUENCE_MAX_LEN + 1]; + TableGenerator::TableState m_tableState; +}; + +QT_END_NAMESPACE + +#endif // QCOMPOSEPLATFORMINPUTCONTEXT_H diff --git a/src/plugins/platforminputcontexts/compose/xkbcommon_workaround.h b/src/plugins/platforminputcontexts/compose/xkbcommon_workaround.h new file mode 100644 index 0000000000..58ce143978 --- /dev/null +++ b/src/plugins/platforminputcontexts/compose/xkbcommon_workaround.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 XKBCOMMON_WORKAROUND_H +#define XKBCOMMON_WORKAROUND_H + +// Function utf32_to_utf8() is borrowed from the libxkbcommon library, +// file keysym-utf.c. The workaround should be removed once the fix from +// https://bugs.freedesktop.org/show_bug.cgi?id=56780 gets released. +static int utf32_to_utf8(uint32_t unichar, char *buffer) +{ + int count, shift, length; + uint8_t head; + + if (unichar <= 0x007f) { + buffer[0] = unichar; + buffer[1] = '\0'; + return 2; + } + else if (unichar <= 0x07FF) { + length = 2; + head = 0xc0; + } + else if (unichar <= 0xffff) { + length = 3; + head = 0xe0; + } + else if (unichar <= 0x1fffff) { + length = 4; + head = 0xf0; + } + else if (unichar <= 0x3ffffff) { + length = 5; + head = 0xf8; + } + else { + length = 6; + head = 0xfc; + } + + for (count = length - 1, shift = 0; count > 0; count--, shift += 6) + buffer[count] = 0x80 | ((unichar >> shift) & 0x3f); + + buffer[0] = head | ((unichar >> shift) & 0x3f); + buffer[length] = '\0'; + + return length + 1; +} + +static bool needWorkaround(uint32_t sym) +{ + /* patch encoding botch */ + if (sym == XKB_KEY_KP_Space) + return true; + + /* special keysyms */ + if ((sym >= XKB_KEY_BackSpace && sym <= XKB_KEY_Clear) || + (sym >= XKB_KEY_KP_Multiply && sym <= XKB_KEY_KP_9) || + sym == XKB_KEY_Return || sym == XKB_KEY_Escape || + sym == XKB_KEY_Delete || sym == XKB_KEY_KP_Tab || + sym == XKB_KEY_KP_Enter || sym == XKB_KEY_KP_Equal) + return true; + + return false; +} + +#endif // XKBCOMMON_WORKAROUND_H diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro index 7b3c6e9c36..fb58de5edc 100644 --- a/src/plugins/platforminputcontexts/platforminputcontexts.pro +++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro @@ -1,4 +1,10 @@ TEMPLATE = subdirs + qtHaveModule(dbus) { !mac:!win32:SUBDIRS += ibus maliit } + +unix:!macx:contains(QT_CONFIG, xkbcommon): { + SUBDIRS += compose +} + diff --git a/src/plugins/platforms/android/src/androidjnimain.cpp b/src/plugins/platforms/android/src/androidjnimain.cpp index f8f077908c..ae94e75e34 100644 --- a/src/plugins/platforms/android/src/androidjnimain.cpp +++ b/src/plugins/platforms/android/src/androidjnimain.cpp @@ -126,8 +126,6 @@ static int m_desktopHeightPixels = 0; static volatile bool m_pauseApplication; -static jmethodID m_setFullScreenMethodID = 0; - static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = 0; @@ -272,24 +270,6 @@ namespace QtAndroid return m_androidPlatformIntegration; } - void setFullScreen(QWidget *widget) - { - AttachedJNIEnv env; - if (!env.jniEnv) - return; - - bool fullScreen = widget->isFullScreen(); - if (!fullScreen) { - foreach (QWidget *w, qApp->topLevelWidgets()) { - fullScreen |= w->isFullScreen(); - if (fullScreen) - break; - } - } - - env.jniEnv->CallStaticVoidMethod(m_applicationClass, m_setFullScreenMethodID, fullScreen); - } - QWindow *topLevelWindowAt(const QPoint &globalPos) { return m_androidPlatformIntegration @@ -674,9 +654,9 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/) if (!m_androidPlatformIntegration) return; - if (qApp != 0) { - foreach (QWidget *w, qApp->topLevelWidgets()) - w->update(); + if (QGuiApplication::instance() != 0) { + foreach (QWindow *w, QGuiApplication::topLevelWindows()) + QWindowSystemInterface::handleExposeEvent(w, QRegion(w->geometry())); } #ifndef ANDROID_PLUGIN_OPENGL @@ -763,7 +743,6 @@ static int registerNatives(JNIEnv *env) } GET_AND_CHECK_STATIC_METHOD(m_redrawSurfaceMethodID, m_applicationClass, "redrawSurface", "(IIII)V"); - GET_AND_CHECK_STATIC_METHOD(m_setFullScreenMethodID, m_applicationClass, "setFullScreen", "(Z)V"); #ifdef ANDROID_PLUGIN_OPENGL FIND_AND_CHECK_CLASS("android/view/Surface"); diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.cpp b/src/plugins/platforms/android/src/qandroidinputcontext.cpp index 37fb605ea8..2180560b04 100644 --- a/src/plugins/platforms/android/src/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/src/qandroidinputcontext.cpp @@ -337,7 +337,10 @@ void QAndroidInputContext::reset() void QAndroidInputContext::commit() { finishComposingText(); +} +void QAndroidInputContext::updateCursorPosition() +{ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); if (!query.isNull()) { const int cursorPos = query->value(Qt::ImCursorPosition).toInt(); @@ -378,6 +381,12 @@ void QAndroidInputContext::showInputPanel() QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); if (query.isNull()) return; + + disconnect(m_updateCursorPosConnection); + if (qGuiApp->focusObject()->metaObject()->indexOfSignal("cursorPositionChanged(int,int)") >= 0) // QLineEdit breaks the pattern + m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged(int,int)), this, SLOT(updateCursorPosition())); + else + m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition())); QRectF itemRect = qGuiApp->inputMethod()->inputItemRectangle(); QRect rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(itemRect).toRect(); QWindow *window = qGuiApp->focusWindow(); diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.h b/src/plugins/platforms/android/src/qandroidinputcontext.h index e2b8107044..482aeffa50 100644 --- a/src/plugins/platforms/android/src/qandroidinputcontext.h +++ b/src/plugins/platforms/android/src/qandroidinputcontext.h @@ -119,10 +119,12 @@ private: private slots: virtual void sendEvent(QObject *receiver, QInputMethodEvent *event); virtual void sendEvent(QObject *receiver, QInputMethodQueryEvent *event); + void updateCursorPosition(); private: ExtractedText m_extractedText; QString m_composingText; + QMetaObject::Connection m_updateCursorPosConnection; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/src.pri b/src/plugins/platforms/android/src/src.pri index 9bf36b2337..76539b50ab 100644 --- a/src/plugins/platforms/android/src/src.pri +++ b/src/plugins/platforms/android/src/src.pri @@ -1,6 +1,6 @@ load(qt_plugin) -QT += core-private gui-private widgets-private platformsupport-private +QT += core-private gui-private platformsupport-private CONFIG += qpa/genericunixfontdatabase diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 55f94df45a..e1569d4f44 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -202,6 +202,13 @@ static void cleanupCocoaApplicationDelegate() if ([self canQuit]) { if (!startedQuit) { startedQuit = true; + // Close open windows. This is done in order to deliver de-expose + // events while the event loop is still running. + const QWindowList topLevels = QGuiApplication::topLevelWindows(); + for (int i = 0; i < topLevels.size(); ++i) { + topLevels.at(i)->close(); + } + QGuiApplication::exit(0); startedQuit = false; } diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 9cc0353dc6..297d81abab 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -586,7 +586,7 @@ QString QCocoaFileDialogHelper::directory() const { QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate); if (delegate) - return QCFString::toQString([delegate->mSavePanel directory]); + return QCFString::toQString([[delegate->mSavePanel directoryURL] path]); return QString(); } diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index d0fcf93b8c..3312de6e3f 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -90,11 +90,28 @@ void QCocoaScreen::updateGeometry() { NSScreen *nsScreen = osScreen(); NSRect frameRect = [nsScreen frame]; - m_geometry = QRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height); - NSRect visibleRect = [nsScreen visibleFrame]; - m_availableGeometry = QRect(visibleRect.origin.x, - frameRect.size.height - (visibleRect.origin.y + visibleRect.size.height), // invert y - visibleRect.size.width, visibleRect.size.height); + + if (m_screenIndex == 0) { + m_geometry = QRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height); + // This is the primary screen, the one that contains the menubar. Its origin should be + // (0, 0), and it's the only one whose available geometry differs from its full geometry. + NSRect visibleRect = [nsScreen visibleFrame]; + m_availableGeometry = QRect(visibleRect.origin.x, + frameRect.size.height - (visibleRect.origin.y + visibleRect.size.height), // invert y + visibleRect.size.width, visibleRect.size.height); + } else { + // NSScreen origin is at the bottom-left corner, QScreen is at the top-left corner. + // When we get the NSScreen frame rect, we need to re-align its origin y coordinate + // w.r.t. the primary screen, whose origin is (0, 0). + NSRect r = [[[NSScreen screens] objectAtIndex:0] frame]; + QRect referenceScreenGeometry = QRect(r.origin.x, r.origin.y, r.size.width, r.size.height); + m_geometry = QRect(frameRect.origin.x, + referenceScreenGeometry.height() - (frameRect.origin.y + frameRect.size.height), + frameRect.size.width, frameRect.size.height); + + // Not primary screen. See above. + m_availableGeometry = m_geometry; + } m_format = QImage::Format_RGB32; m_depth = NSBitsPerPixelFromDepth([nsScreen depth]); diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/plugins/platforms/cocoa/qcocoakeymapper.h index 324b753131..0629de9317 100644 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.h +++ b/src/plugins/platforms/cocoa/qcocoakeymapper.h @@ -99,7 +99,6 @@ private: const UCKeyboardLayout *unicode; void *other; } keyboard_layout_format; - KeyboardLayoutRef currentKeyboardLayout; KeyboardLayoutKind keyboard_kind; UInt32 keyboard_dead; KeyboardLayoutItem *keyLayout[256]; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index bdcad6f490..40cffab3c9 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -195,7 +195,7 @@ NSMenuItem *QCocoaMenuItem::sync() QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); switch (m_role) { case ApplicationSpecificRole: - mergeItem = [loader appSpecificMenuItem]; + mergeItem = [loader appSpecificMenuItem:reinterpret_cast<NSInteger>(this)]; break; case AboutRole: mergeItem = [loader aboutMenuItem]; diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.h b/src/plugins/platforms/cocoa/qcocoamenuloader.h index f95f684e8c..a45ec0fa89 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.h +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h @@ -79,7 +79,7 @@ - (NSMenuItem *)aboutMenuItem; - (NSMenuItem *)aboutQtMenuItem; - (NSMenuItem *)hideMenuItem; -- (NSMenuItem *)appSpecificMenuItem; +- (NSMenuItem *)appSpecificMenuItem:(NSInteger)tag; - (IBAction)terminate:(id)sender; - (IBAction)orderFrontStandardAboutPanel:(id)sender; - (IBAction)hideOtherApplications:(id)sender; diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index 2a9dcec64b..726fe5c6d2 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -246,11 +246,17 @@ QT_END_NAMESPACE return [[hideItem retain] autorelease]; } -- (NSMenuItem *)appSpecificMenuItem +- (NSMenuItem *)appSpecificMenuItem:(NSInteger)tag { + NSMenuItem *item = [appMenu itemWithTag:tag]; + + // No reason to create the item if it already exists. See QTBUG-27202. + if (item) + return [[item retain] autorelease]; + // Create an App-Specific menu item, insert it into the menu and return // it as an autorelease item. - NSMenuItem *item = [[NSMenuItem alloc] init]; + item = [[NSMenuItem alloc] init]; NSInteger location; if (lastAppSpecificItem == nil) { diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 2f79b49534..ca84312059 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -52,6 +52,7 @@ class QWidget; class QPlatformPrinterSupport; class QPrintEngine; class QPlatformMenu; +class QPlatformMenuBar; class QCocoaNativeInterface : public QPlatformNativeInterface { @@ -99,12 +100,27 @@ private: // Dock menu support static void setDockMenu(QPlatformMenu *platformMenu); + // Function to return NSMenu * from QPlatformMenu + static void *qMenuToNSMenu(QPlatformMenu *platformMenu); + + // Function to return NSMenu * from QPlatformMenuBar + static void *qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar); + // QImage <-> CGImage conversion functions static CGImageRef qImageToCGImage(const QImage &image); static QImage cgImageToQImage(CGImageRef image); // Embedding NSViews as child QWindows static void setWindowContentView(QPlatformWindow *window, void *nsViewContentView); + + // 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. + // + // The registration is ref-counted: multiple widgets can enable + // touch events, which then will be delivered until the widget + // deregisters. + static void registerTouchWindow(QWindow *window, bool enable); }; #endif // QCOCOANATIVEINTERFACE_H diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 9990537c1f..ededb63487 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -109,12 +109,18 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerDraggedTypes); if (resource.toLower() == "setdockmenu") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setDockMenu); + if (resource.toLower() == "qmenutonsmenu") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuToNSMenu); + if (resource.toLower() == "qmenubartonsmenu") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuBarToNSMenu); if (resource.toLower() == "qimagetocgimage") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qImageToCGImage); if (resource.toLower() == "cgimagetoqimage") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::cgImageToQImage); if (resource.toLower() == "setwindowcontentview") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setWindowContentView); + if (resource.toLower() == "registertouchwindow") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerTouchWindow); return 0; } @@ -187,7 +193,24 @@ void QCocoaNativeInterface::setDockMenu(QPlatformMenu *platformMenu) QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu); NSMenu *menu = cocoaPlatformMenu->nsMenu(); // setDockMenu seems to be undocumented, but this is what Qt 4 did. - [NSApp setDockMenu: menu]; + if ([NSApp respondsToSelector:@selector(setDockMenu:)]) + [NSApp setDockMenu: menu]; + else + qWarning("Could not set dock menu: [NSApp setDockMenu] is not available."); +} + +void *QCocoaNativeInterface::qMenuToNSMenu(QPlatformMenu *platformMenu) +{ + QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu); + NSMenu *menu = cocoaPlatformMenu->nsMenu(); + return reinterpret_cast<void *>(menu); +} + +void *QCocoaNativeInterface::qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar) +{ + QCocoaMenuBar *cocoaPlatformMenuBar = static_cast<QCocoaMenuBar *>(platformMenuBar); + NSMenu *menu = cocoaPlatformMenuBar->nsMenu(); + return reinterpret_cast<void *>(menu); } CGImageRef QCocoaNativeInterface::qImageToCGImage(const QImage &image) @@ -206,4 +229,11 @@ void QCocoaNativeInterface::setWindowContentView(QPlatformWindow *window, void * cocoaPlatformWindow->setContentView(reinterpret_cast<NSView *>(contentView)); } +void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable) +{ + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + if (cocoaWindow) + cocoaWindow->registerTouch(enable); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index 6f8d0fa22a..8b0c14a984 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -179,14 +179,14 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes() if (mac_widget_colors[i].active != 0) { qc = qt_mac_colorForThemeTextColor(mac_widget_colors[i].active); pal.setColor(QPalette::Active, QPalette::Text, qc); + pal.setColor(QPalette::Inactive, QPalette::Text, qc); pal.setColor(QPalette::Active, QPalette::WindowText, qc); + pal.setColor(QPalette::Inactive, QPalette::WindowText, qc); pal.setColor(QPalette::Active, QPalette::HighlightedText, qc); + pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc); qc = qt_mac_colorForThemeTextColor(mac_widget_colors[i].inactive); - pal.setColor(QPalette::Inactive, QPalette::Text, qc); pal.setColor(QPalette::Disabled, QPalette::Text, qc); - pal.setColor(QPalette::Inactive, QPalette::WindowText, qc); pal.setColor(QPalette::Disabled, QPalette::WindowText, qc); - pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc); pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc); } if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette) { diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 84dcaad206..e1de5f0add 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -108,6 +108,8 @@ public: void setWindowIcon(const QIcon &icon); void raise(); void lower(); + bool isExposed() const; + bool isOpaque() const; void propagateSizeHints(); void setOpacity(qreal level); void setMask(const QRegion ®ion); @@ -145,7 +147,12 @@ public: void setMenubar(QCocoaMenuBar *mb); QCocoaMenuBar *menubar() const; + void registerTouch(bool enable); + qreal devicePixelRatio() const; + void exposeWindow(); + void obscureWindow(); + QWindow *childWindowAt(QPoint windowPoint); protected: // NSWindow handling. The QCocoaWindow/QNSView can either be displayed // in an existing NSWindow or in one created by Qt. @@ -158,8 +165,6 @@ protected: QCocoaWindow *parentCocoaWindow() const; void syncWindowState(Qt::WindowState newState); - void updateOpaque(); - // private: public: // for QNSView friend class QCocoaBackingStore; @@ -175,6 +180,7 @@ public: // for QNSView Qt::WindowState m_synchedWindowState; Qt::WindowModality m_windowModality; QPointer<QWindow> m_activePopupWindow; + QPointer<QWindow> m_underMouseWindow; bool m_inConstructor; QCocoaGLContext *m_glContext; @@ -182,6 +188,8 @@ public: // for QNSView bool m_hasModalSession; bool m_frameStrutEventsEnabled; + bool m_isExposed; + int m_registerTouchCount; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 5eab036661..e74f9dcfe0 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -200,6 +200,8 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_menubar(0) , m_hasModalSession(false) , m_frameStrutEventsEnabled(false) + , m_isExposed(false) + , m_registerTouchCount(0) { #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::QCocoaWindow" << this; @@ -260,6 +262,9 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) void QCocoaWindow::setVisible(bool visible) { QCocoaAutoReleasePool pool; + QCocoaWindow *parentCocoaWindow = 0; + if (window()->transientParent()) + parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle()); #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::setVisible" << window() << visible; #endif @@ -267,10 +272,7 @@ void QCocoaWindow::setVisible(bool visible) // We need to recreate if the modality has changed as the style mask will need updating if (m_windowModality != window()->modality()) recreateWindow(parent()); - QCocoaWindow *parentCocoaWindow = 0; - if (window()->transientParent()) { - parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle()); - + if (parentCocoaWindow) { // The parent window might have moved while this window was hidden, // update the window geometry if there is a parent. setGeometry(window()->geometry()); @@ -280,13 +282,20 @@ void QCocoaWindow::setVisible(bool visible) if (window()->type() == Qt::Popup) { // qDebug() << "transientParent and popup" << window()->type() << Qt::Popup << (window()->type() & Qt::Popup); parentCocoaWindow->m_activePopupWindow = window(); + // QTBUG-30266: a window should not be resizable while a transient popup is open + // Since this isn't a native popup, the window manager doesn't close the popup when you click outside + [parentCocoaWindow->m_nsWindow setStyleMask: + (parentCocoaWindow->windowStyleMask(parentCocoaWindow->m_windowFlags) & ~NSResizableWindowMask)]; } } - // Make sure the QWindow has a frame ready before we show the NSWindow. - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); - QWindowSystemInterface::flushWindowSystemEvents(); + // This call is here to handle initial window show correctly: + // - top-level windows need to have backing store content ready when the + // window is shown, sendin the expose event here makes that more likely. + // - QNSViews for child windows are initialy not hidden and won't get the + // viewDidUnhide message. + exposeWindow(); if (m_nsWindow) { // setWindowState might have been called while the window was hidden and @@ -338,8 +347,9 @@ void QCocoaWindow::setVisible(bool visible) } else { [m_contentView setHidden:YES]; } - if (!QCoreApplication::closingDown()) - QWindowSystemInterface::handleExposeEvent(window(), QRegion()); + if (parentCocoaWindow && window()->type() == Qt::Popup) + // QTBUG-30266: a window should not be resizable while a transient popup is open + [parentCocoaWindow->m_nsWindow setStyleMask:parentCocoaWindow->windowStyleMask(parentCocoaWindow->m_windowFlags)]; } } @@ -376,7 +386,7 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) NSInteger styleMask = NSBorderlessWindowMask; if ((type & Qt::Popup) == Qt::Popup) { - if (!windowIsPopupType(type)) + if (!windowIsPopupType(type) && !(flags & Qt::FramelessWindowHint)) styleMask = (NSUtilityWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask); } else { @@ -491,6 +501,19 @@ void QCocoaWindow::lower() [m_nsWindow orderBack: m_nsWindow]; } +bool QCocoaWindow::isExposed() const +{ + return m_isExposed; +} + +bool QCocoaWindow::isOpaque() const +{ + bool translucent = (window()->format().alphaBufferSize() > 0 + || window()->opacity() < 1 + || (m_qtView && [m_qtView hasMask])); + return !translucent; +} + void QCocoaWindow::propagateSizeHints() { QCocoaAutoReleasePool pool; @@ -529,20 +552,11 @@ void QCocoaWindow::propagateSizeHints() } } -void QCocoaWindow::updateOpaque() -{ - bool translucent = window()->format().alphaBufferSize() > 0 - || window()->opacity() < 1 - || (m_contentView && [m_contentView hasMask]); - [m_nsWindow setOpaque:!translucent]; -} - - void QCocoaWindow::setOpacity(qreal level) { if (m_nsWindow) { [m_nsWindow setAlphaValue:level]; - updateOpaque(); + [m_nsWindow setOpaque: isOpaque()]; } } @@ -552,7 +566,7 @@ void QCocoaWindow::setMask(const QRegion ®ion) [m_nsWindow setBackgroundColor:[NSColor clearColor]]; [m_qtView setMaskRegion:®ion]; - updateOpaque(); + [m_nsWindow setOpaque: isOpaque()]; } bool QCocoaWindow::setKeyboardGrabEnabled(bool grab) @@ -886,6 +900,15 @@ QCocoaMenuBar *QCocoaWindow::menubar() const return m_menubar; } +void QCocoaWindow::registerTouch(bool enable) +{ + m_registerTouchCount += enable ? 1 : -1; + if (m_registerTouchCount == 1) + [m_contentView setAcceptsTouchEvents:YES]; + else if (m_registerTouchCount == 0) + [m_contentView setAcceptsTouchEvents:NO]; +} + qreal QCocoaWindow::devicePixelRatio() const { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 @@ -898,6 +921,37 @@ qreal QCocoaWindow::devicePixelRatio() const } } +void QCocoaWindow::exposeWindow() +{ + if (!m_isExposed) { + m_isExposed = true; + QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); + } +} + +void QCocoaWindow::obscureWindow() +{ + if (m_isExposed) { + m_isExposed = false; + QWindowSystemInterface::handleExposeEvent(window(), QRegion()); + } +} + +QWindow *QCocoaWindow::childWindowAt(QPoint windowPoint) +{ + QWindow *targetWindow = window(); + foreach (QObject *child, targetWindow->children()) { + if (QWindow *childWindow = qobject_cast<QWindow *>(child)) { + if (childWindow->geometry().contains(windowPoint)) { + QCocoaWindow* platformWindow = static_cast<QCocoaWindow*>(childWindow->handle()); + targetWindow = platformWindow->childWindowAt(windowPoint - childWindow->position()); + } + } + } + + return targetWindow; +} + QMargins QCocoaWindow::frameMargins() const { NSRect frameW = [m_nsWindow frame]; diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 5fe0861e0a..e7ea3d8f8d 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -59,6 +59,7 @@ QT_END_NAMESPACE QPoint m_backingStoreOffset; CGImageRef m_maskImage; uchar *m_maskData; + bool m_shouldInvalidateWindowShadow; QWindow *m_window; QCocoaWindow *m_platformWindow; Qt::MouseButtons m_buttons; @@ -76,14 +77,18 @@ QT_END_NAMESPACE - (void)setQCocoaGLContext:(QCocoaGLContext *)context; - (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset; - (void)setMaskRegion:(const QRegion *)region; +- (void)invalidateWindowShadowIfNeeded; - (void)drawRect:(NSRect)dirtyRect; - (void)updateGeometry; - (void)windowNotification : (NSNotification *) windowNotification; +- (void)viewDidHide; +- (void)viewDidUnhide; - (BOOL)isFlipped; - (BOOL)acceptsFirstResponder; - (BOOL)becomeFirstResponder; - (BOOL)hasMask; +- (BOOL)isOpaque; - (void)resetMouseButtons; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 18714ddbae..3046b898df 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -80,6 +80,7 @@ static QTouchDevice *touchDevice = 0; m_backingStore = 0; m_maskImage = 0; m_maskData = 0; + m_shouldInvalidateWindowShadow = false; m_window = 0; m_buttons = Qt::NoButton; m_sendKeyEvent = false; @@ -240,6 +241,7 @@ static QTouchDevice *touchDevice = 0; // Send a geometry change event to Qt, if it's ready to handle events if (!m_platformWindow->m_inConstructor) { QWindowSystemInterface::handleGeometryChange(m_window, geometry); + QWindowSystemInterface::handleExposeEvent(m_window, geometry); QWindowSystemInterface::flushWindowSystemEvents(); } } @@ -266,10 +268,10 @@ static QTouchDevice *touchDevice = 0; QWindowSystemInterface::handleWindowStateChanged(m_window, Qt::WindowMinimized); } else if (notificationName == NSWindowDidDeminiaturizeNotification) { QWindowSystemInterface::handleWindowStateChanged(m_window, Qt::WindowNoState); - // Qt expects an expose event after restore/deminiaturize. This also needs - // to be a non-synchronous event to make sure it gets processed after - // the state change event sent above. - QWindowSystemInterface::handleExposeEvent(m_window, QRegion(m_window->geometry())); + } else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) { + m_platformWindow->obscureWindow(); + } else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) { + m_platformWindow->exposeWindow(); } else { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 @@ -285,6 +287,16 @@ static QTouchDevice *touchDevice = 0; } } +- (void)viewDidHide +{ + m_platformWindow->obscureWindow(); +} + +- (void)viewDidUnhide +{ + m_platformWindow->exposeWindow(); +} + - (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset { m_backingStore = backingStore; @@ -298,15 +310,21 @@ static QTouchDevice *touchDevice = 0; return m_maskData != 0; } +- (BOOL) isOpaque +{ + return m_platformWindow->isOpaque(); +} + - (void) setMaskRegion:(const QRegion *)region { + m_shouldInvalidateWindowShadow = true; if (m_maskImage) CGImageRelease(m_maskImage); if (region->isEmpty()) { m_maskImage = 0; } - const QRect &rect = qt_mac_toQRect([self frame]); + const QRect &rect = region->boundingRect(); QImage maskImage(rect.size(), QImage::Format_RGB888); maskImage.fill(Qt::white); QPainter p(&maskImage); @@ -319,6 +337,14 @@ static QTouchDevice *touchDevice = 0; m_maskImage = qt_mac_toCGImage(maskImage, true, &m_maskData); } +- (void)invalidateWindowShadowIfNeeded +{ + if (m_shouldInvalidateWindowShadow && m_platformWindow->m_nsWindow) { + [m_platformWindow->m_nsWindow invalidateShadow]; + m_shouldInvalidateWindowShadow = false; + } +} + - (void) drawRect:(NSRect)dirtyRect { if (!m_backingStore) @@ -373,6 +399,8 @@ static QTouchDevice *touchDevice = 0; CGContextRestoreGState(cgContext); CGImageRelease(cleanImg); CGImageRelease(subMask); + + [self invalidateWindowShadowIfNeeded]; } - (BOOL) isFlipped @@ -382,6 +410,8 @@ static QTouchDevice *touchDevice = 0; - (BOOL)becomeFirstResponder { + if (m_window->flags() & Qt::WindowTransparentForInput) + return NO; QWindow *focusWindow = m_window; // For widgets we need to do a bit of trickery as the window @@ -399,6 +429,8 @@ static QTouchDevice *touchDevice = 0; { if (m_window->flags() & Qt::WindowDoesNotAcceptFocus) return NO; + if (m_window->flags() & Qt::WindowTransparentForInput) + return NO; if ((m_window->flags() & Qt::ToolTip) == Qt::ToolTip) return NO; return YES; @@ -406,7 +438,9 @@ static QTouchDevice *touchDevice = 0; - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { - Q_UNUSED(theEvent); + Q_UNUSED(theEvent) + if (m_window->flags() & Qt::WindowTransparentForInput) + return NO; return YES; } @@ -511,6 +545,8 @@ static QTouchDevice *touchDevice = 0; - (void)mouseDown:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super mouseDown:theEvent]; m_sendUpAsRightButton = false; if (m_platformWindow->m_activePopupWindow) { QWindowSystemInterface::handleCloseEvent(m_platformWindow->m_activePopupWindow); @@ -535,6 +571,8 @@ static QTouchDevice *touchDevice = 0; - (void)mouseDragged:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super mouseDragged:theEvent]; if (!(m_buttons & Qt::LeftButton)) qWarning("QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)"); [self handleMouseEvent:theEvent]; @@ -542,6 +580,8 @@ static QTouchDevice *touchDevice = 0; - (void)mouseUp:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super mouseUp:theEvent]; if (m_sendUpAsRightButton) { m_buttons &= ~Qt::RightButton; m_sendUpAsRightButton = false; @@ -559,6 +599,7 @@ static QTouchDevice *touchDevice = 0; if (NSIsEmptyRect([self visibleRect])) return; + // Remove current trakcing areas: QCocoaAutoReleasePool pool; if (NSArray *trackingArray = [self trackingAreas]) { NSUInteger size = [trackingArray count]; @@ -571,7 +612,7 @@ static QTouchDevice *touchDevice = 0; // Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should // only be turned on if mouseTracking, hover is on or a tool tip is set. // Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to - // turn it on in ALL case. That means EVERY QCocoaView gets to pay the cost of + // turn it on in ALL case. That means EVERY QWindow gets to pay the cost of // mouse moves delivered to it (Apple recommends keeping it OFF because there // is a performance hit). So it goes. NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp @@ -586,30 +627,74 @@ static QTouchDevice *touchDevice = 0; - (void)mouseMoved:(NSEvent *)theEvent { - [self handleMouseEvent:theEvent]; + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super mouseMoved:theEvent]; + + QPoint windowPoint, screenPoint; + [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint); + + // Top-level windows generate enter-leave events for sub-windows. + // Qt wants to know which window (if any) will be entered at the + // the time of the leave. This is dificult to accomplish by + // handling mouseEnter and mouseLeave envents, since they are sent + // individually to different views. + if (m_platformWindow->m_nsWindow && childWindow) { + if (childWindow != m_platformWindow->m_underMouseWindow) { + QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_underMouseWindow, windowPoint, screenPoint); + m_platformWindow->m_underMouseWindow = childWindow; + } + } + + // Cocoa keeps firing mouse move events for obscured parent views. Qt should not + // send those events so filter them out here. + if (childWindow != m_window) + return; + + [self handleMouseEvent: theEvent]; } - (void)mouseEntered:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super mouseEntered:theEvent]; + + // Top-level windows generate enter events for sub-windows. + if (!m_platformWindow->m_nsWindow) + return; + QPoint windowPoint, screenPoint; [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; - QWindowSystemInterface::handleEnterEvent(m_window, windowPoint, screenPoint); + m_platformWindow->m_underMouseWindow = m_platformWindow->childWindowAt(windowPoint); + QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_underMouseWindow, windowPoint, screenPoint); } - (void)mouseExited:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super mouseExited:theEvent]; Q_UNUSED(theEvent); - QWindowSystemInterface::handleLeaveEvent(m_window); + + // Top-level windows generate leave events for sub-windows. + if (!m_platformWindow->m_nsWindow) + return; + + QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_underMouseWindow); + m_platformWindow->m_underMouseWindow = 0; } - (void)rightMouseDown:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super rightMouseDown:theEvent]; m_buttons |= Qt::RightButton; [self handleMouseEvent:theEvent]; } - (void)rightMouseDragged:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super rightMouseDragged:theEvent]; if (!(m_buttons & Qt::RightButton)) qWarning("QNSView rightMouseDragged: Internal mouse button tracking invalid (missing Qt::RightButton)"); [self handleMouseEvent:theEvent]; @@ -617,18 +702,24 @@ static QTouchDevice *touchDevice = 0; - (void)rightMouseUp:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super rightMouseUp:theEvent]; m_buttons &= ~Qt::RightButton; [self handleMouseEvent:theEvent]; } - (void)otherMouseDown:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super otherMouseDown:theEvent]; m_buttons |= cocoaButton2QtButton([theEvent buttonNumber]); [self handleMouseEvent:theEvent]; } - (void)otherMouseDragged:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super otherMouseDragged:theEvent]; if (!(m_buttons & ~(Qt::LeftButton | Qt::RightButton))) qWarning("QNSView otherMouseDragged: Internal mouse button tracking invalid (missing Qt::MiddleButton or Qt::ExtraButton*)"); [self handleMouseEvent:theEvent]; @@ -636,6 +727,8 @@ static QTouchDevice *touchDevice = 0; - (void)otherMouseUp:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super otherMouseUp:theEvent]; m_buttons &= ~cocoaButton2QtButton([theEvent buttonNumber]); [self handleMouseEvent:theEvent]; } @@ -671,6 +764,8 @@ static QTouchDevice *touchDevice = 0; #ifndef QT_NO_WHEELEVENT - (void)scrollWheel:(NSEvent *)theEvent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super scrollWheel:theEvent]; const EventRef carbonEvent = (EventRef)[theEvent eventRef]; const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0; const bool scrollEvent = carbonEventKind == kEventMouseScroll; @@ -778,6 +873,7 @@ static QTouchDevice *touchDevice = 0; ulong nativeModifiers = [nsevent modifierFlags]; Qt::KeyboardModifiers modifiers = [self convertKeyModifiers: nativeModifiers]; NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers]; + NSString *characters = [nsevent characters]; // [from Qt 4 impl] There is no way to get the scan code from carbon. But we cannot // use the value 0, since it indicates that the event originates from somewhere @@ -790,9 +886,12 @@ static QTouchDevice *touchDevice = 0; QChar ch; int keyCode; - if ([charactersIgnoringModifiers length] > 0) { - // convert the first character into a key code - ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); + 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 = [self convertKeyCode:ch]; } else { // might be a dead key @@ -808,7 +907,7 @@ static QTouchDevice *touchDevice = 0; // ignore text for the U+F700-U+F8FF range. This is used by Cocoa when // delivering function keys (e.g. arrow keys, backspace, F1-F35, etc.) if ([charactersIgnoringModifiers length] == 1 && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff)) - text = QCFString::toQString([nsevent characters]); + text = QCFString::toQString(characters); if (m_composingText.isEmpty()) m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutEvent(m_window, timestamp, keyCode, modifiers, text); @@ -836,11 +935,15 @@ static QTouchDevice *touchDevice = 0; - (void)keyDown:(NSEvent *)nsevent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super keyDown:nsevent]; [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; } - (void)keyUp:(NSEvent *)nsevent { + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super keyUp:nsevent]; [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)]; } diff --git a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp index 08da98d690..5a94bff14e 100644 --- a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp +++ b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp @@ -44,7 +44,7 @@ #include <QDebug> #include <QUrl> -#ifdef QQNXNAVIGATOR_DEBUG +#if defined(QQNXNAVIGATOR_DEBUG) #define qNavigatorDebug qDebug #else #define qNavigatorDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp index 2ef548f59f..26543a8d56 100644 --- a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp +++ b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp @@ -53,7 +53,7 @@ #include <bps/navigator.h> #include <bps/screen.h> -#ifdef QQNXBPSEVENTFILTER_DEBUG +#if defined(QQNXBPSEVENTFILTER_DEBUG) #define qBpsEventFilterDebug qDebug #else #define qBpsEventFilterDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxbuffer.cpp b/src/plugins/platforms/qnx/qqnxbuffer.cpp index 9007af7f70..c5e99a2001 100644 --- a/src/plugins/platforms/qnx/qqnxbuffer.cpp +++ b/src/plugins/platforms/qnx/qqnxbuffer.cpp @@ -46,7 +46,7 @@ #include <errno.h> #include <sys/mman.h> -#ifdef QQNXBUFFER_DEBUG +#if defined(QQNXBUFFER_DEBUG) #define qBufferDebug qDebug #else #define qBufferDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp index 152b732556..2f531efd8b 100644 --- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp +++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp @@ -49,7 +49,7 @@ #include <QtCore/QSocketNotifier> #include <QtCore/private/qcore_unix_p.h> -#ifdef QQNXBUTTON_DEBUG +#if defined(QQNXBUTTON_DEBUG) #define qButtonDebug qDebug #else #define qButtonDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxclipboard.cpp b/src/plugins/platforms/qnx/qqnxclipboard.cpp index 8286febd35..dfd1345eed 100644 --- a/src/plugins/platforms/qnx/qqnxclipboard.cpp +++ b/src/plugins/platforms/qnx/qqnxclipboard.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#ifndef QT_NO_CLIPBOARD +#if !defined(QT_NO_CLIPBOARD) #include "qqnxclipboard.h" @@ -53,7 +53,7 @@ #include <clipboard/clipboard.h> #include <errno.h> -#ifdef QQNXCLIPBOARD_DEBUG +#if defined(QQNXCLIPBOARD_DEBUG) #define qClipboardDebug qDebug #else #define qClipboardDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxclipboard.h b/src/plugins/platforms/qnx/qqnxclipboard.h index e069355adc..561b57299e 100644 --- a/src/plugins/platforms/qnx/qqnxclipboard.h +++ b/src/plugins/platforms/qnx/qqnxclipboard.h @@ -44,7 +44,7 @@ #include <QtCore/qglobal.h> -#ifndef QT_NO_CLIPBOARD +#if !defined(QT_NO_CLIPBOARD) #include <qpa/qplatformclipboard.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxcursor.cpp b/src/plugins/platforms/qnx/qqnxcursor.cpp index 4fdff666d7..3cf857bb27 100644 --- a/src/plugins/platforms/qnx/qqnxcursor.cpp +++ b/src/plugins/platforms/qnx/qqnxcursor.cpp @@ -43,7 +43,7 @@ #include <QtCore/QDebug> -#ifdef QQNXCURSOR_DEBUG +#if defined(QQNXCURSOR_DEBUG) #define qCursorDebug qDebug #else #define qCursorDebug QT_NO_QDEBUG_MACRO @@ -55,7 +55,7 @@ QQnxCursor::QQnxCursor() { } -#ifndef QT_NO_CURSOR +#if !defined(QT_NO_CURSOR) void QQnxCursor::changeCursor(QCursor *windowCursor, QWindow *window) { Q_UNUSED(windowCursor); diff --git a/src/plugins/platforms/qnx/qqnxcursor.h b/src/plugins/platforms/qnx/qqnxcursor.h index 5d6a8b2c30..b62c299040 100644 --- a/src/plugins/platforms/qnx/qqnxcursor.h +++ b/src/plugins/platforms/qnx/qqnxcursor.h @@ -51,7 +51,7 @@ class QQnxCursor : public QPlatformCursor public: QQnxCursor(); -#ifndef QT_NO_CURSOR +#if !defined(QT_NO_CURSOR) void changeCursor(QCursor *windowCursor, QWindow *window); #endif void setPos(const QPoint &pos); diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper_playbook.cpp b/src/plugins/platforms/qnx/qqnxfiledialoghelper_playbook.cpp index 4f61e0c587..12e8d8afbf 100644 --- a/src/plugins/platforms/qnx/qqnxfiledialoghelper_playbook.cpp +++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper_playbook.cpp @@ -51,7 +51,7 @@ #include <QTimer> #include <QWindow> -#ifdef QQNXFILEDIALOGHELPER_DEBUG +#if defined(QQNXFILEDIALOGHELPER_DEBUG) #define qFileDialogHelperDebug qDebug #else #define qFileDialogHelperDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index 1c2ec23fa9..f77bb73614 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -50,7 +50,7 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QScreen> -#ifdef QQNXGLCONTEXT_DEBUG +#if defined(QQNXGLCONTEXT_DEBUG) #define qGLContextDebug qDebug #else #define qGLContextDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp index 0d8f430c73..97a361158e 100644 --- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp +++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp @@ -61,13 +61,13 @@ #include <process.h> #include <sys/keycodes.h> -#ifdef QQNXINPUTCONTEXT_IMF_EVENT_DEBUG +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) #define qInputContextIMFEventDebug qDebug #else #define qInputContextIMFEventDebug QT_NO_QDEBUG_MACRO #endif -#ifdef QQNXINPUTCONTEXT_DEBUG +#if defined(QQNXINPUTCONTEXT_DEBUG) #define qInputContextDebug qDebug #else #define qInputContextDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp index 71b925357a..f444d34b5e 100644 --- a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp +++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp @@ -47,7 +47,7 @@ #include <QtCore/QDebug> #include <QtGui/QGuiApplication> -#ifdef QQNXINPUTCONTEXT_DEBUG +#if defined(QQNXINPUTCONTEXT_DEBUG) #define qInputContextDebug qDebug #else #define qInputContextDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index 2d5c2e54e7..5ea4fef698 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -96,7 +96,7 @@ #include <errno.h> -#ifdef QQNXINTEGRATION_DEBUG +#if defined(QQNXINTEGRATION_DEBUG) #define qIntegrationDebug qDebug #else #define qIntegrationDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp index d561482b47..30dbb330d7 100644 --- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp +++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp @@ -45,7 +45,7 @@ #include <QGuiApplication> #include <qpa/qwindowsysteminterface.h> -#ifdef QQNXNAVIGATOREVENTHANDLER_DEBUG +#if defined(QQNXNAVIGATOREVENTHANDLER_DEBUG) #define qNavigatorEventHandlerDebug qDebug #else #define qNavigatorEventHandlerDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp index 9fa8294815..640944fb45 100644 --- a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp +++ b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp @@ -55,7 +55,7 @@ #include <sys/types.h> #include <sys/stat.h> -#ifdef QQNXNAVIGATOREVENTNOTIFIER_DEBUG +#if defined(QQNXNAVIGATOREVENTNOTIFIER_DEBUG) #define qNavigatorEventNotifierDebug qDebug #else #define qNavigatorEventNotifierDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp index 92a94e0a39..1656ab029b 100644 --- a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp +++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp @@ -44,7 +44,7 @@ #include <QDebug> #include <private/qcore_unix_p.h> -#ifdef QQNXNAVIGATOR_DEBUG +#if defined(QQNXNAVIGATOR_DEBUG) #define qNavigatorDebug qDebug #else #define qNavigatorDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp index 47a72f173b..7204e5bce9 100644 --- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp +++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp @@ -46,7 +46,7 @@ #include <errno.h> -#ifdef QQNXRASTERBACKINGSTORE_DEBUG +#if defined(QQNXRASTERBACKINGSTORE_DEBUG) #define qRasterBackingStoreDebug qDebug #else #define qRasterBackingStoreDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxrootwindow.cpp b/src/plugins/platforms/qnx/qqnxrootwindow.cpp index b01d468647..198801a832 100644 --- a/src/plugins/platforms/qnx/qqnxrootwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxrootwindow.cpp @@ -46,7 +46,7 @@ #include <QtCore/QUuid> #include <QtCore/QDebug> -#ifdef QQNXROOTWINDOW_DEBUG +#if defined(QQNXROOTWINDOW_DEBUG) #define qRootWindowDebug qDebug #else #define qRootWindowDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index f9efbde40c..7614abdc6a 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -49,7 +49,7 @@ #include <errno.h> -#ifdef QQNXSCREEN_DEBUG +#if defined(QQNXSCREEN_DEBUG) #define qScreenDebug qDebug #else #define qScreenDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp index 2d3c7608bf..57cfdc5eb6 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp @@ -50,7 +50,7 @@ #include <errno.h> #include <sys/keycodes.h> -#ifdef QQNXSCREENEVENT_DEBUG +#if defined(QQNXSCREENEVENT_DEBUG) #define qScreenEventDebug qDebug #else #define qScreenEventDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp index 8f262a7083..f3f660bc03 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp @@ -49,7 +49,7 @@ #include <cctype> -#ifdef QQNXSCREENEVENTTHREAD_DEBUG +#if defined(QQNXSCREENEVENTTHREAD_DEBUG) #define qScreenEventThreadDebug qDebug #else #define qScreenEventThreadDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxtheme.cpp b/src/plugins/platforms/qnx/qqnxtheme.cpp index ae9acd845e..c0aef07bd9 100644 --- a/src/plugins/platforms/qnx/qqnxtheme.cpp +++ b/src/plugins/platforms/qnx/qqnxtheme.cpp @@ -76,10 +76,11 @@ QPlatformDialogHelper *QQnxTheme::createPlatformDialogHelper(DialogType type) co switch (type) { case QPlatformTheme::FileDialog: return new QQnxFileDialogHelper(m_integration); -#ifndef QT_NO_COLORDIALOG +#endif +#if !defined(QT_NO_COLORDIALOG) case QPlatformTheme::ColorDialog: #endif -#ifndef QT_NO_FONTDIALOG +#if !defined(QT_NO_FONTDIALOG) case QPlatformTheme::FontDialog: #endif default: diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp index 3d2f49aa6c..11eb4a5082 100644 --- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp @@ -47,7 +47,7 @@ #include <bps/locale.h> #include <bps/virtualkeyboard.h> -#ifdef QQNXVIRTUALKEYBOARD_DEBUG +#if defined(QQNXVIRTUALKEYBOARD_DEBUG) #define qVirtualKeyboardDebug qDebug #else #define qVirtualKeyboardDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp index ab912927bb..e810b47c22 100644 --- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp @@ -56,7 +56,7 @@ #include <sys/types.h> #include <unistd.h> -#ifdef QQNXVIRTUALKEYBOARD_DEBUG +#if defined(QQNXVIRTUALKEYBOARD_DEBUG) #define qVirtualKeyboardDebug qDebug #else #define qVirtualKeyboardDebug QT_NO_QDEBUG_MACRO diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h index eb41b2efd0..6048868b08 100644 --- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef VIRTUALKEYBOARDPPS_H_ -#define VIRTUALKEYBOARDPPS_H_ +#ifndef VIRTUALKEYBOARDPPS_H +#define VIRTUALKEYBOARDPPS_H #include "qqnxabstractvirtualkeyboard.h" @@ -97,4 +97,4 @@ private: static const size_t ms_bufferSize; }; -#endif /* VIRTUALKEYBOARDPPS_H_ */ +#endif // VIRTUALKEYBOARDPPS_H diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 51435a1e55..f1bebee9b2 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include "qqnxwindow.h" -#ifndef QT_NO_OPENGL +#if !defined(QT_NO_OPENGL) #include "qqnxglcontext.h" #endif #include "qqnxintegration.h" @@ -53,12 +53,12 @@ #include <errno.h> -#ifdef Q_OS_BLACKBERRY +#if defined(Q_OS_BLACKBERRY) #include <sys/pps.h> #include <bps/navigator.h> #endif -#ifdef QQNXWINDOW_DEBUG +#if defined(QQNXWINDOW_DEBUG) #define qWindowDebug qDebug #else #define qWindowDebug QT_NO_QDEBUG_MACRO @@ -72,7 +72,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) m_window(0), m_currentBufferIndex(-1), m_previousBufferIndex(-1), -#ifndef QT_NO_OPENGL +#if !defined(QT_NO_OPENGL) m_platformOpenGLContext(0), #endif m_screen(0), @@ -353,7 +353,7 @@ void QQnxWindow::setBufferSize(const QSize &size) // Create window buffers if they do not exist if (m_bufferSize.isEmpty()) { -#ifndef QT_NO_OPENGL +#if !defined(QT_NO_OPENGL) // Get pixel format from EGL config if using OpenGL; // otherwise inherit pixel format of window's screen if (m_platformOpenGLContext != 0) { @@ -666,7 +666,7 @@ void QQnxWindow::gainedFocus() QWindowSystemInterface::handleWindowActivated(window()); } -#ifndef QT_NO_OPENGL +#if !defined(QT_NO_OPENGL) void QQnxWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext) { // This function does not take ownership of the platform gl context. diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index ad136227e3..4a327fd54b 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -49,7 +49,7 @@ #include <QtGui/QImage> #include <QtCore/QMutex> -#ifndef QT_NO_OPENGL +#if !defined(QT_NO_OPENGL) #include <EGL/egl.h> #endif @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE // all surfaces double buffered #define MAX_BUFFER_COUNT 2 -#ifndef QT_NO_OPENGL +#if !defined(QT_NO_OPENGL) class QQnxGLContext; #endif class QQnxScreen; @@ -108,7 +108,7 @@ public: QQnxScreen *screen() const { return m_screen; } const QList<QQnxWindow*>& children() const { return m_childWindows; } -#ifndef QT_NO_OPENGL +#if !defined(QT_NO_OPENGL) void setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext); QQnxGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; } #endif @@ -144,7 +144,7 @@ private: QRegion m_previousDirty; QRegion m_scrolled; -#ifndef QT_NO_OPENGL +#if !defined(QT_NO_OPENGL) QQnxGLContext *m_platformOpenGLContext; #endif QQnxScreen *m_screen; diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index fb08daa38e..44e715d0ce 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -645,7 +645,8 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, l QPoint topLeft = accessible->rect().topLeft(); - if (QAccessibleInterface *parentIface = accessible->parent()) + QAccessibleInterface *parentIface = accessible->parent(); + if (parentIface && parentIface->isValid()) topLeft -= parentIface->rect().topLeft(); *x = topLeft.x(); @@ -1596,7 +1597,7 @@ uint QWindowsIA2Accessible::uniqueID() const if (!uid) { QAccessibleInterface *acc = accessible; QVector<int> indexOfNodes; - while (acc && !acc->object()) { + while (acc && acc->isValid() && !acc->object()) { QAccessibleInterface *par = acc->parent(); indexOfNodes.append(par->indexOfChild(acc)); if (acc != accessible) diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp index 752b9e7c20..79d0934ebb 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp @@ -169,7 +169,9 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) // An event has to be associated with a window, // so find the first parent that is a widget and that has a WId QAccessibleInterface *iface = event->accessibleInterface(); - QWindow *window = iface ? QWindowsAccessibility::windowHelper(iface) : 0; + if (!iface) // ### This should not happen, maybe make it an assert. + return; + QWindow *window = QWindowsAccessibility::windowHelper(iface); delete iface; if (!window) { @@ -213,7 +215,7 @@ QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface) QWindow *window = iface->window(); if (!window) { QAccessibleInterface *acc = iface->parent(); - while (acc && !window) { + while (acc && acc->isValid() && !window) { window = acc->window(); QAccessibleInterface *par = acc->parent(); delete acc; diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index bb5d5d13a7..9958615d45 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -612,7 +612,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA case NAVDIR_PREVIOUS: if (!varStart.lVal){ QAccessibleInterface *parent = accessible->parent(); - if (parent) { + if (parent && parent->isValid()) { int index = parent->indexOfChild(accessible); index += (navDir == NAVDIR_NEXT) ? 1 : -1; if (index >= 0 && index < parent->childCount()) @@ -631,8 +631,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA case NAVDIR_UP: case NAVDIR_DOWN: case NAVDIR_LEFT: - case NAVDIR_RIGHT: - if (QAccessibleInterface *pIface = accessible->parent()) { + case NAVDIR_RIGHT: { + QAccessibleInterface *pIface = accessible->parent(); + if (pIface && pIface->isValid()) { const int indexOfOurself = pIface->indexOfChild(accessible); QRect startg = accessible->rect(); QPoint startc = startg.center(); @@ -709,6 +710,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA delete pIface; acc = candidate; } + } break; default: break; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 5cc5230832..8565bf0204 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -1340,7 +1340,9 @@ static inline QString appendSuffix(const QString &fileName, const QString &filte if (suffixPos < 0) return fileName; suffixPos += 3; - int endPos = filter.indexOf(QLatin1Char(';'), suffixPos + 1); + 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) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 6cbe3e8cf7..9b2b67619d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -791,13 +791,16 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : m_iconSmall(0), m_iconBig(0) { - if (aWindow->surfaceType() == QWindow::OpenGLSurface) - setFlag(OpenGLSurface); // Clear the creation context as the window can be found in QWindowsContext's map. QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>()); QWindowsContext::instance()->addWindow(m_data.hwnd, this); + const Qt::WindowType type = aWindow->type(); + if (type == Qt::Desktop) + return; // No further handling for Qt::Desktop + if (aWindow->surfaceType() == QWindow::OpenGLSurface) + setFlag(OpenGLSurface); if (aWindow->isTopLevel()) { - switch (aWindow->type()) { + switch (type) { case Qt::Window: case Qt::Dialog: case Qt::Sheet: @@ -811,8 +814,13 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : } } #ifndef Q_OS_WINCE - if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) - QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, 0); + if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) { + if (QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, 0)) { + setFlag(TouchRegistered); + } else { + qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(aWindow->objectName())); + } + } #endif // !Q_OS_WINCE setWindowState(aWindow->windowState()); const qreal opacity = qt_window_private(aWindow)->opacity; @@ -824,7 +832,7 @@ QWindowsWindow::~QWindowsWindow() { #ifndef Q_OS_WINCE QWindowSystemInterface::flushWindowSystemEvents(); - if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) + if (testFlag(TouchRegistered)) QWindowsContext::user32dll.unregisterTouchWindow(m_data.hwnd); #endif // !Q_OS_WINCE destroyWindow(); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 87397f1c1d..1148440f05 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -131,7 +131,8 @@ public: FrameStrutEventsEnabled = 0x200, SynchronousGeometryChangeEvent = 0x400, WithinSetStyle = 0x800, - WithinDestroy = 0x1000 + WithinDestroy = 0x1000, + TouchRegistered = 0x2000 }; struct WindowData diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index ff40c6a9ab..3fd2ca70e3 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -490,7 +490,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0); } - if (cursor && cshape >= 0 && cshape < Qt::LastCursor) { + if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) { const char *name = cursorNames[cshape]; xcb_xfixes_set_cursor_name(conn, cursor, strlen(name), name); } diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 20d312216a..5af6a9ec9d 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -186,6 +186,7 @@ QXcbWindow::QXcbWindow(QWindow *window) , m_gravity(XCB_GRAVITY_STATIC) , m_mapped(false) , m_transparent(false) + , m_usingSyncProtocol(false) , m_deferredActivation(false) , m_embedded(false) , m_netWmUserTimeWindow(XCB_NONE) @@ -354,7 +355,9 @@ void QXcbWindow::create() properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS); properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING); - if (m_screen->syncRequestSupported()) + m_usingSyncProtocol = m_screen->syncRequestSupported() && window()->surfaceType() != QSurface::OpenGLSurface; + + if (m_usingSyncProtocol) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST); if (window()->flags() & Qt::WindowContextHelpButtonHint) @@ -371,7 +374,7 @@ void QXcbWindow::create() m_syncValue.hi = 0; m_syncValue.lo = 0; - if (m_screen->syncRequestSupported()) { + if (m_usingSyncProtocol) { m_syncCounter = xcb_generate_id(xcb_connection()); Q_XCB_CALL(xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue)); @@ -463,7 +466,7 @@ void QXcbWindow::destroy() if (connection()->focusWindow() == this) connection()->setFocusWindow(0); - if (m_syncCounter && m_screen->syncRequestSupported()) + if (m_syncCounter && m_usingSyncProtocol) Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter)); if (m_window) { if (m_netWmUserTimeWindow) { @@ -1824,7 +1827,7 @@ void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *) void QXcbWindow::updateSyncRequestCounter() { - if (m_screen->syncRequestSupported() && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) { + if (m_usingSyncProtocol && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) { Q_XCB_CALL(xcb_sync_set_counter(xcb_connection(), m_syncCounter, m_syncValue)); xcb_flush(xcb_connection()); connection()->sync(); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 1810a58c7b..f4bd2d96ff 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -189,6 +189,7 @@ private: bool m_mapped; bool m_transparent; + bool m_usingSyncProtocol; bool m_deferredActivation; bool m_deferredExpose; bool m_configureNotifyPending; |