diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-04-29 14:17:08 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-04-29 14:17:09 +0200 |
commit | 85e3c53e5c5e2de993c90ece324a68d0ff62f417 (patch) | |
tree | 6f078576f01f18afcdae773e48664640ce795abe /src | |
parent | 2e749c089f6fd93909e7cd4cc8129f2969b35185 (diff) | |
parent | 7f943968ade6a65321d4a00822f5b3a034a19e0c (diff) | |
download | qtbase-85e3c53e5c5e2de993c90ece324a68d0ff62f417.tar.gz |
Merge remote-tracking branch 'origin/stable' into dev
Change-Id: I2a54058b64ac69c78b4120fdaf09b96e025a4c6c
Diffstat (limited to 'src')
116 files changed, 1369 insertions, 428 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def index dc5900854a..0f6caf17a3 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def @@ -180,3 +180,5 @@ EXPORTS glGetCurrentContext @147 NONAME glGetProcAddress@4 @148 NONAME glBindTexImage@4 @158 NONAME + glCreateRenderer @177 NONAME + glDestroyRenderer @178 NONAME
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def index 610e5e1173..dd92a2a12b 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def @@ -180,3 +180,5 @@ EXPORTS glGetCurrentContext @147 NONAME glGetProcAddress@4 @148 NONAME glBindTexImage@4 @158 NONAME + glCreateRenderer @177 NONAME + glDestroyRenderer @178 NONAME
\ No newline at end of file diff --git a/src/3rdparty/angle/src/libGLESv2/mathutil.h b/src/3rdparty/angle/src/libGLESv2/mathutil.h index 672c443c11..bb48b94eaf 100644 --- a/src/3rdparty/angle/src/libGLESv2/mathutil.h +++ b/src/3rdparty/angle/src/libGLESv2/mathutil.h @@ -9,6 +9,8 @@ #ifndef LIBGLESV2_MATHUTIL_H_ #define LIBGLESV2_MATHUTIL_H_ +#include <intrin.h> + #include "common/system.h" #include "common/debug.h" diff --git a/src/angle/patches/0010-Add-missing-intrin.h-include-for-__cpuid.patch b/src/angle/patches/0010-Add-missing-intrin.h-include-for-__cpuid.patch new file mode 100644 index 0000000000..ebe3de4dc9 --- /dev/null +++ b/src/angle/patches/0010-Add-missing-intrin.h-include-for-__cpuid.patch @@ -0,0 +1,30 @@ +From 142312b5cbea10257b6d3693b48817ae657018eb Mon Sep 17 00:00:00 2001 +From: Kai Koehne <kai.koehne@digia.com> +Date: Mon, 22 Apr 2013 16:36:17 +0200 +Subject: [PATCH] Add missing intrin.h include for __cpuid + +This is already fixed upstream in + +https://codereview.appspot.com/8615046/patch/1/2 + +Change-Id: I4b9e865f6b5622c484418a8381334381bc256887 +--- + src/3rdparty/angle/src/libGLESv2/mathutil.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/3rdparty/angle/src/libGLESv2/mathutil.h b/src/3rdparty/angle/src/libGLESv2/mathutil.h +index 672c443..bb48b94 100644 +--- a/src/3rdparty/angle/src/libGLESv2/mathutil.h ++++ b/src/3rdparty/angle/src/libGLESv2/mathutil.h +@@ -9,6 +9,8 @@ + #ifndef LIBGLESV2_MATHUTIL_H_ + #define LIBGLESV2_MATHUTIL_H_ + ++#include <intrin.h> ++ + #include "common/system.h" + #include "common/debug.h" + +-- +1.8.1.msysgit.1 + diff --git a/src/angle/src/libGLESv2/libGLESv2.pro b/src/angle/src/libGLESv2/libGLESv2.pro index 681cd1be19..d12202f33b 100644 --- a/src/angle/src/libGLESv2/libGLESv2.pro +++ b/src/angle/src/libGLESv2/libGLESv2.pro @@ -87,7 +87,7 @@ SOURCES += \ $$ANGLE_DIR/src/libGLESv2/renderer/VertexBuffer.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/VertexDataManager.cpp -sse2:SOURCES += $$ANGLE_DIR/src/libGLESv2/renderer/ImageSSE2.cpp +SSE2_SOURCES += $$ANGLE_DIR/src/libGLESv2/renderer/ImageSSE2.cpp angle_d3d11 { HEADERS += \ diff --git a/src/corelib/Qt5CTestMacros.cmake b/src/corelib/Qt5CTestMacros.cmake index 126a348b47..51537a3904 100644 --- a/src/corelib/Qt5CTestMacros.cmake +++ b/src/corelib/Qt5CTestMacros.cmake @@ -38,6 +38,10 @@ foreach(module ${CMAKE_MODULES_UNDER_TEST}) ) endforeach() +if(CMAKE_CROSSCOMPILING AND CMAKE_FIND_ROOT_PATH) + list(APPEND BUILD_OPTIONS_LIST "-DCMAKE_CXX_LINK_FLAGS=--sysroot=\"${CMAKE_FIND_ROOT_PATH}\"") +endif() + macro(expect_pass _dir) string(REPLACE "(" "_" testname "${_dir}") string(REPLACE ")" "_" testname "${testname}") diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h index 4722fe2282..6332e2d761 100644 --- a/src/corelib/global/qflags.h +++ b/src/corelib/global/qflags.h @@ -79,7 +79,7 @@ class QFlags { Q_STATIC_ASSERT_X((sizeof(Enum) <= sizeof(int)), "QFlags uses an int as storage, so an enum with underlying " - "long long would overflow. Qt 5.1 will have support for 64bit enums."); + "long long will overflow."); struct Private; typedef int (Private::*Zero); public: diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index f130288a24..95d9baafd5 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -138,6 +138,10 @@ public: Q_DECLARE_FLAGS(KeyboardModifiers, KeyboardModifier) //shorter names for shortcuts + // The use of all-caps identifiers has the potential for clashing with + // user-defined or third-party macros. More so when the identifiers are not + // "namespace"-prefixed. This is considered bad practice and is why + // KeypadModifier was not added to the Modifier enum. enum Modifier { META = Qt::MetaModifier, SHIFT = Qt::ShiftModifier, diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 484dcbf22e..da38f8ae21 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -817,8 +817,12 @@ QDataStream &QDataStream::operator>>(double &f) Reads the '\\0'-terminated string \a s from the stream and returns a reference to the stream. - Space for the string is allocated using \c new -- the caller must - destroy it with \c{delete[]}. + The string is deserialized using \c{readBytes()}. + + Space for the string is allocated using \c{new []} -- the caller must + destroy it with \c{delete []}. + + \sa readBytes(), readRawData() */ QDataStream &QDataStream::operator>>(char *&s) @@ -832,8 +836,8 @@ QDataStream &QDataStream::operator>>(char *&s) Reads the buffer \a s from the stream and returns a reference to the stream. - The buffer \a s is allocated using \c new. Destroy it with the \c - delete[] operator. + The buffer \a s is allocated using \c{new []}. Destroy it with the + \c{delete []} operator. The \a l parameter is set to the length of the buffer. If the string read is empty, \a l is set to 0 and \a s is set to @@ -1102,7 +1106,9 @@ QDataStream &QDataStream::operator<<(double f) Writes the '\\0'-terminated string \a s to the stream and returns a reference to the stream. - The string is serialized using writeBytes(). + The string is serialized using \c{writeBytes()}. + + \sa writeBytes(), writeRawData() */ QDataStream &QDataStream::operator<<(const char *s) diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 7fcb4154f2..addcd772ab 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -187,6 +187,8 @@ uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) cons QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) const { Q_ASSERT(fileEngine); // should never be called when using the native FS + if (fileTimes.size() != 3) + fileTimes.resize(3); if (!cache_enabled) clearFlags(); uint cf; diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h index 1b254f6e85..442e6b5ef0 100644 --- a/src/corelib/io/qfileinfo_p.h +++ b/src/corelib/io/qfileinfo_p.h @@ -58,6 +58,7 @@ #include "qatomic.h" #include "qshareddata.h" #include "qfilesystemengine_p.h" +#include "qvector.h" #include <QtCore/private/qabstractfileengine_p.h> #include <QtCore/private/qfilesystementry_p.h> @@ -152,7 +153,12 @@ public: bool cache_enabled : 1; mutable uint fileFlags; mutable qint64 fileSize; - mutable QDateTime fileTimes[3]; + // ### Qt6: FIXME: This vector is essentially a plain array + // mutable QDateTime fileTimes[3], but the array is slower + // to initialize than the QVector as QDateTime has a pimpl. + // In Qt 6, QDateTime should inline its data members, + // and this here can be an array again. + mutable QVector<QDateTime> fileTimes; inline bool getCachedFlag(uint c) const { return cache_enabled ? (cachedFlags & c) : 0; } inline void setCachedFlag(uint c) const diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 3993cf5002..59b6db7c79 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -125,16 +125,15 @@ QT_BEGIN_NAMESPACE The environment of the calling process can be obtained using QProcessEnvironment::systemEnvironment(). - On Unix systems, the variable names are case-sensitive. For that reason, - this class will not touch the names of the variables. Note as well that + On Unix systems, the variable names are case-sensitive. Note that the Unix environment allows both variable names and contents to contain arbitrary - binary data (except for the NUL character), but this is not supported by - QProcessEnvironment. This class only supports names and values that are - encodable by the current locale settings (see QTextCodec::codecForLocale). + binary data (except for the NUL character). QProcessEnvironment will preserve + such variables, but does not support manipulating variables whose names or + values are not encodable by the current locale settings (see + QTextCodec::codecForLocale). - On Windows, the variable names are case-insensitive. Therefore, - QProcessEnvironment will always uppercase the names and do case-insensitive - comparisons. + On Windows, the variable names are case-insensitive, but case-preserving. + QProcessEnvironment behaves accordingly. On Windows CE, the concept of environment does not exist. This class will keep the values set for compatibility with other platforms, but the values @@ -298,9 +297,6 @@ void QProcessEnvironment::clear() Returns true if the environment variable of name \a name is found in this QProcessEnvironment object. - On Windows, variable names are case-insensitive, so the key is converted - to uppercase before searching. On other systems, names are case-sensitive - so no trasformation is applied. \sa insert(), value() */ @@ -314,10 +310,6 @@ bool QProcessEnvironment::contains(const QString &name) const into this QProcessEnvironment object. If that variable already existed, it is replaced by the new value. - On Windows, variable names are case-insensitive, so this function always - uppercases the variable name before inserting. On other systems, names - are case-sensitive, so no transformation is applied. - On most systems, inserting a variable with no contents will have the same effect for applications as if the variable had not been set at all. However, to guarantee that there are no incompatibilities, to remove a @@ -336,9 +328,6 @@ void QProcessEnvironment::insert(const QString &name, const QString &value) QProcessEnvironment object. If that variable did not exist before, nothing happens. - On Windows, variable names are case-insensitive, so the key is converted - to uppercase before searching. On other systems, names are case-sensitive - so no trasformation is applied. \sa contains(), insert(), value() */ @@ -353,10 +342,6 @@ void QProcessEnvironment::remove(const QString &name) \a name and returns its value. If the variable is not found in this object, then \a defaultValue is returned instead. - On Windows, variable names are case-insensitive, so the key is converted - to uppercase before searching. On other systems, names are case-sensitive - so no trasformation is applied. - \sa contains(), insert(), remove() */ QString QProcessEnvironment::value(const QString &name, const QString &defaultValue) const @@ -376,10 +361,10 @@ QString QProcessEnvironment::value(const QString &name, const QString &defaultVa each environment variable that is set. The environment variable's name and its value are separated by an equal character ('='). - The QStringList contents returned by this function are suitable for use - with the QProcess::setEnvironment function. However, it is recommended - to use QProcess::setProcessEnvironment instead since that will avoid - unnecessary copying of the data. + The QStringList contents returned by this function are suitable for + presentation. + Use with the QProcess::setEnvironment function is not recommended due to + potential encoding problems under Unix, and worse performance. \sa systemEnvironment(), QProcess::systemEnvironment(), QProcess::environment(), QProcess::setEnvironment() diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h index a0ac33e8a8..16f30fffd6 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.h +++ b/src/corelib/itemmodels/qabstractitemmodel.h @@ -410,7 +410,7 @@ inline bool QAbstractItemModel::moveRow(const QModelIndex &sourceParent, int sou { return moveRows(sourceParent, sourceRow, 1, destinationParent, destinationChild); } inline bool QAbstractItemModel::moveColumn(const QModelIndex &sourceParent, int sourceColumn, const QModelIndex &destinationParent, int destinationChild) -{ return moveRows(sourceParent, sourceColumn, 1, destinationParent, destinationChild); } +{ return moveColumns(sourceParent, sourceColumn, 1, destinationParent, destinationChild); } inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, void *adata) const { return QModelIndex(arow, acolumn, adata, this); } inline QModelIndex QAbstractItemModel::createIndex(int arow, int acolumn, quintptr aid) const diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h index ec9c6fd91b..0492886cfd 100644 --- a/src/corelib/thread/qorderedmutexlocker_p.h +++ b/src/corelib/thread/qorderedmutexlocker_p.h @@ -53,10 +53,10 @@ // We mean it. // -QT_BEGIN_NAMESPACE - #include <QtCore/qmutex.h> +QT_BEGIN_NAMESPACE + /* Locks 2 mutexes in a defined order, avoiding a recursive lock if we're trying to lock the same mutex twice. diff --git a/src/corelib/thread/qwaitcondition.qdoc b/src/corelib/thread/qwaitcondition.qdoc index 68788e0b3f..9aa633a210 100644 --- a/src/corelib/thread/qwaitcondition.qdoc +++ b/src/corelib/thread/qwaitcondition.qdoc @@ -124,8 +124,8 @@ Releases the \a lockedMutex and waits on the wait condition. The \a lockedMutex must be initially locked by the calling thread. If \a - lockedMutex is not in a locked state, this function returns - immediately. If \a lockedMutex is a recursive mutex, this function + lockedMutex is not in a locked state, the behavior is undefined. If + \a lockedMutex is a recursive mutex, this function returns immediately. The \a lockedMutex will be unlocked, and the calling thread will block until either of these conditions is met: diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h index d1cc10c877..5c1668033c 100644 --- a/src/corelib/tools/qdatetime.h +++ b/src/corelib/tools/qdatetime.h @@ -262,6 +262,10 @@ public: private: friend class QDateTimePrivate; void detach(); + + // ### Qt6: Using a private here has high impact on runtime + // on users such as QFileInfo. In Qt 6, the data members + // should be inlined. QExplicitlySharedDataPointer<QDateTimePrivate> d; #ifndef QT_NO_DATASTREAM diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 4aaa1af688..b5f983899a 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -284,51 +284,51 @@ QLocaleId QLocaleId::withLikelySubtagsRemoved() const return max; } -QString QLocaleId::bcp47Name() const +QByteArray QLocaleId::name(char separator) const { if (language_id == QLocale::AnyLanguage) - return QString(); + return QByteArray(); if (language_id == QLocale::C) - return QStringLiteral("C"); + return QByteArrayLiteral("C"); - const unsigned char *lang = language_code_list + 3*uint(language_id); + const unsigned char *lang = language_code_list + 3 * language_id; const unsigned char *script = - (script_id != QLocale::AnyScript ? script_code_list + 4*uint(script_id) : 0); + (script_id != QLocale::AnyScript ? script_code_list + 4 * script_id : 0); const unsigned char *country = - (country_id != QLocale::AnyCountry ? country_code_list + 3*uint(country_id) : 0); + (country_id != QLocale::AnyCountry ? country_code_list + 3 * country_id : 0); char len = (lang[2] != 0 ? 3 : 2) + (script ? 4+1 : 0) + (country ? (country[2] != 0 ? 3 : 2)+1 : 0); - QString name(len, Qt::Uninitialized); - QChar *uc = name.data(); - *uc++ = ushort(lang[0]); - *uc++ = ushort(lang[1]); + QByteArray name(len, Qt::Uninitialized); + char *uc = name.data(); + *uc++ = lang[0]; + *uc++ = lang[1]; if (lang[2] != 0) - *uc++ = ushort(lang[2]); + *uc++ = lang[2]; if (script) { - *uc++ = QLatin1Char('-'); - *uc++ = ushort(script[0]); - *uc++ = ushort(script[1]); - *uc++ = ushort(script[2]); - *uc++ = ushort(script[3]); + *uc++ = separator; + *uc++ = script[0]; + *uc++ = script[1]; + *uc++ = script[2]; + *uc++ = script[3]; } if (country) { - *uc++ = QLatin1Char('-'); - *uc++ = ushort(country[0]); - *uc++ = ushort(country[1]); + *uc++ = separator; + *uc++ = country[0]; + *uc++ = country[1]; if (country[2] != 0) - *uc++ = ushort(country[2]); + *uc++ = country[2]; } return name; } -QString QLocalePrivate::bcp47Name() const +QByteArray QLocalePrivate::bcp47Name(char separator) const { if (m_data->m_language_id == QLocale::AnyLanguage) - return QString(); + return QByteArray(); if (m_data->m_language_id == QLocale::C) - return QStringLiteral("C"); + return QByteArrayLiteral("C"); QLocaleId localeId = QLocaleId::fromIds(m_data->m_language_id, m_data->m_script_id, m_data->m_country_id); - return localeId.withLikelySubtagsRemoved().bcp47Name(); + return localeId.withLikelySubtagsRemoved().name(separator); } const QLocaleData *QLocaleData::findLocaleData(QLocale::Language language, QLocale::Script script, QLocale::Country country) @@ -1080,7 +1080,7 @@ QString QLocale::name() const */ QString QLocale::bcp47Name() const { - return d->bcp47Name(); + return QString::fromLatin1(d->bcp47Name()); } /*! @@ -2494,7 +2494,7 @@ QString QLocale::toUpper(const QString &str) const { #ifdef QT_USE_ICU bool ok = true; - QString result = QIcu::toUpper(d->m_localeID, str, &ok); + QString result = QIcu::toUpper(d->bcp47Name('_'), str, &ok); if (ok) return result; // else fall through and use Qt's toUpper @@ -2511,7 +2511,7 @@ QString QLocale::toLower(const QString &str) const { #ifdef QT_USE_ICU bool ok = true; - QString result = QIcu::toLower(d->m_localeID, str, &ok); + const QString result = QIcu::toLower(d->bcp47Name('_'), str, &ok); if (ok) return result; // else fall through and use Qt's toUpper @@ -3662,14 +3662,14 @@ QStringList QLocale::uiLanguages() const const QLocaleId min = max.withLikelySubtagsRemoved(); QStringList uiLanguages; - uiLanguages.append(min.bcp47Name()); + uiLanguages.append(QString::fromLatin1(min.name())); if (id.script_id) { id.script_id = 0; if (id != min && id.withLikelySubtagsAdded() == max) - uiLanguages.append(id.bcp47Name()); + uiLanguages.append(QString::fromLatin1(id.name())); } if (max != min && max != id) - uiLanguages.append(max.bcp47Name()); + uiLanguages.append(QString::fromLatin1(max.name())); return uiLanguages; } diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index 4c0432bba7..9674342307 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -151,7 +151,7 @@ struct QLocaleId QLocaleId withLikelySubtagsAdded() const; QLocaleId withLikelySubtagsRemoved() const; - QString bcp47Name() const; + QByteArray name(char separator = '-') const; ushort language_id, script_id, country_id; }; @@ -212,8 +212,6 @@ public: : m_index(index), m_numberOptions(numberOptions) { m_data = dataPointerForIndex(index); - m_localeID = bcp47Name().toLatin1(); - m_localeID.replace('-','_'); } ~QLocalePrivate() @@ -232,7 +230,7 @@ public: quint16 languageId() const { return m_data->m_language_id; } quint16 countryId() const { return m_data->m_country_id; } - QString bcp47Name() const; + QByteArray bcp47Name(char separator = '-') const; // ### QByteArray::fromRawData would be more optimal inline QString languageCode() const { return QLocalePrivate::languageToCode(QLocale::Language(m_data->m_language_id)); } @@ -334,11 +332,9 @@ public: QString dateTimeToString(const QString &format, const QDate *date, const QTime *time, const QLocale *q) const; - friend class QLocale; quint16 m_index; quint16 m_numberOptions; const QLocaleData *m_data; - QByteArray m_localeID; }; inline char QLocalePrivate::digitToCLocale(QChar in) const diff --git a/src/dbus/doc/qtdbus.qdocconf b/src/dbus/doc/qtdbus.qdocconf index f3b4c0f1d7..b47e02ff43 100644 --- a/src/dbus/doc/qtdbus.qdocconf +++ b/src/dbus/doc/qtdbus.qdocconf @@ -1,7 +1,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) # Name of the project which must match the outputdir. Determines the .index file -project = qtdbus +project = QtDBus # Directories in which to search for files to document and images. # By default set to the root directory of the project for sources @@ -29,23 +29,23 @@ depends += qtcore # Defines the name of the project. You cannot use operators (+, =, -) in # the name. Properties for this project are set using a qhp.<projectname>.property # format. -qhp.projects = qtdbus +qhp.projects = QtDBus # Sets the name of the output qhp file. -qhp.qtdbus.file = qtdbus.qhp +qhp.QtDBus.file = qtdbus.qhp # Namespace for the output file. This namespace is used to distinguish between # different documentation files in Creator/Assistant. -qhp.qtdbus.namespace = org.qt-project.qtdbus.$QT_VERSION_TAG +qhp.QtDBus.namespace = org.qt-project.qtdbus.$QT_VERSION_TAG # Title for the package, will be the main title for the package in # Assistant/Creator. -qhp.qtdbus.indexTitle = Qt D-Bus +qhp.QtDBus.indexTitle = Qt D-Bus # Only update the name of the project for the next variables. -qhp.qtdbus.virtualFolder = qtdbus -qhp.qtdbus.subprojects = classes -qhp.qtdbus.subprojects.classes.title = C++ Classes -qhp.qtdbus.subprojects.classes.indexTitle = Qt D-Bus C++ Classes -qhp.qtdbus.subprojects.classes.selectors = class fake:headerfile -qhp.qtdbus.subprojects.classes.sortPages = true +qhp.QtDBus.virtualFolder = qtdbus +qhp.QtDBus.subprojects = classes +qhp.QtDBus.subprojects.classes.title = C++ Classes +qhp.QtDBus.subprojects.classes.indexTitle = Qt D-Bus C++ Classes +qhp.QtDBus.subprojects.classes.selectors = class fake:headerfile +qhp.QtDBus.subprojects.classes.sortPages = true diff --git a/src/gui/Qt5GuiConfigExtras.cmake.in b/src/gui/Qt5GuiConfigExtras.cmake.in index d9313d4364..f385fa0f6e 100644 --- a/src/gui/Qt5GuiConfigExtras.cmake.in +++ b/src/gui/Qt5GuiConfigExtras.cmake.in @@ -1,5 +1,48 @@ -!!IF !contains(QT_CONFIG, angle) +!!IF !isEmpty(CMAKE_ANGLE_EGL_DLL_RELEASE) + +!!IF isEmpty(CMAKE_INCLUDE_DIR_IS_ABSOLUTE) +set(Qt5Gui_EGL_INCLUDE_DIRS \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$$CMAKE_INCLUDE_DIR\") +!!ELSE +set(Qt5Gui_EGL_INCLUDE_DIRS \"$$CMAKE_INCLUDE_DIR\") +!!ENDIF + +set(Qt5Gui_OPENGL_INCLUDE_DIRS ${Qt5Gui_EGL_INCLUDE_DIRS}) + +macro(_populate_qt5gui_gl_target_properties TargetName Configuration LIB_LOCATION IMPLIB_LOCATION) + set_property(TARGET Qt5::${TargetName} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${Configuration}) + + set_target_properties(Qt5::${TargetName} PROPERTIES +!!IF isEmpty(CMAKE_LIB_DIR_IS_ABSOLUTE) + \"IMPORTED_LOCATION_${Configuration}\" \"${_qt5Gui_install_prefix}/$${CMAKE_LIB_DIR}${LIB_LOCATION}\" +!!ELSE + \"IMPORTED_LOCATION_${Configuration}\" \"$${CMAKE_LIB_DIR}${LIB_LOCATION}\" +!!ENDIF +!!IF isEmpty(CMAKE_LIB_DIR_IS_ABSOLUTE) + \"IMPORTED_IMPLIB_${Configuration}\" \"${_qt5Gui_install_prefix}/$${CMAKE_LIB_DIR}${IMPLIB_LOCATION}\" +!!ELSE + \"IMPORTED_IMPLIB_${Configuration}\" \"$${CMAKE_LIB_DIR}${IMPLIB_LOCATION}\" +!!ENDIF + ) +endmacro() + +add_library(Qt5::Gui_EGL SHARED IMPORTED) +_populate_qt5gui_gl_target_properties(Gui_EGL RELEASE $${CMAKE_ANGLE_EGL_DLL_RELEASE} $${CMAKE_ANGLE_EGL_IMPLIB_RELEASE}) +add_library(Qt5::Gui_GLESv2 SHARED IMPORTED) +_populate_qt5gui_gl_target_properties(Gui_GLESv2 RELEASE $${CMAKE_ANGLE_GLES2_DLL_RELEASE} $${CMAKE_ANGLE_GLES2_IMPLIB_RELEASE}) + +set_property(TARGET Qt5::Gui_EGL APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Qt5Gui_EGL_INCLUDE_DIRS}) +set_property(TARGET Qt5::Gui_GLESv2 APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Qt5Gui_OPENGL_INCLUDE_DIRS}) + +!!IF !isEmpty(CMAKE_DEBUG_TYPE) +_populate_qt5gui_gl_target_properties(Gui_EGL DEBUG $${CMAKE_ANGLE_EGL_DLL_DEBUG} $${CMAKE_ANGLE_EGL_IMPLIB_DEBUG}) +_populate_qt5gui_gl_target_properties(Gui_GLESv2 DEBUG $${CMAKE_ANGLE_GLES2_DLL_DEBUG} $${CMAKE_ANGLE_GLES2_IMPLIB_DEBUG}) +!!ENDIF + +set(Qt5Gui_EGL_LIBRARIES Qt5::Gui_EGL) +set(Qt5Gui_OPENGL_LIBRARIES Qt5::Gui_GLESv2) + +!!ELSE !!IF !isEmpty(CMAKE_GL_INCDIRS) @@ -17,4 +60,67 @@ unset(_qt5gui_OPENGL_INCLUDE_DIR CACHE) !!ENDIF +macro(_qt5gui_find_extra_libs Name Libs LibDir IncDirs) + set(Qt5Gui_${Name}_LIBRARIES) + set(Qt5Gui_EGL_INCLUDE_DIRS ${IncDirs}) + foreach(_lib ${Libs}) + string(REGEX REPLACE "[^_A-Za-z0-9]" "_" _cmake_lib_name ${_lib}) + if (NOT TARGET Qt5::Gui_${_cmake_lib_name}) + find_library(Qt5Gui_${_cmake_lib_name}_LIBRARY ${_lib} +!!IF !isEmpty(CROSS_COMPILE) + PATHS \"${LibDir}\" NO_DEFAULT_PATH +!!ENDIF + ) +!!IF mac + set(Qt5Gui_${_cmake_lib_name}_LIBRARY "${Qt5Gui_${_cmake_lib_name}_LIBRARY}/${_lib}") +!!ENDIF + if (NOT Qt5Gui_${_cmake_lib_name}_LIBRARY) + message(FATAL_ERROR \"Failed to find \\\"${_lib}\\\" in \\\"${LibDir}\\\", using the CMAKE_FIND_ROOT_PATH \\\"${CMAKE_FIND_ROOT_PATH}\\\".\") + endif() + add_library(Qt5::Gui_${_cmake_lib_name} SHARED IMPORTED) + set_property(TARGET Qt5::Gui_${_cmake_lib_name} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${IncDirs}) + + set_property(TARGET Qt5::Gui_${_cmake_lib_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_property(TARGET Qt5::Gui_${_cmake_lib_name} PROPERTY IMPORTED_LOCATION_RELEASE \"${Qt5Gui_${_cmake_lib_name}_LIBRARY}\") +!!IF !isEmpty(CMAKE_WINDOWS_BUILD) + set_property(TARGET Qt5::Gui_${_cmake_lib_name} PROPERTY IMPORTED_IMPLIB_RELEASE \"${Qt5Gui_${_cmake_lib_name}_LIBRARY}\") +!!ENDIF + unset(Qt5Gui_${_cmake_lib_name}_LIBRARY CACHE) + + find_library(Qt5Gui_${_cmake_lib_name}_LIBRARY_DEBUG ${_lib}d + PATHS \"${LibDir}\" NO_DEFAULT_PATH) + if (Qt5Gui_${_cmake_lib_name}_LIBRARY_DEBUG) + set_property(TARGET Qt5::Gui_${_cmake_lib_name} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_property(TARGET Qt5::Gui_${_cmake_lib_name} PROPERTY IMPORTED_LOCATION_DEBUG \"${Qt5Gui_${_cmake_lib_name}_LIBRARY_DEBUG}\") +!!IF !isEmpty(CMAKE_WINDOWS_BUILD) + set_property(TARGET Qt5::Gui_${_cmake_lib_name} PROPERTY IMPORTED_IMPLIB_DEBUG \"${Qt5Gui_${_cmake_lib_name}_LIBRARY_DEBUG}\") +!!ENDIF + endif() + unset(Qt5Gui_${_cmake_lib_name}_LIBRARY_DEBUG CACHE) + endif() + list(APPEND Qt5Gui_${Name}_LIBRARIES Qt5::Gui_${_cmake_lib_name}) + endforeach() +endmacro() + + +!!IF !isEmpty(CMAKE_EGL_LIBS) +_qt5gui_find_extra_libs(EGL \"$$CMAKE_EGL_LIBS\" \"$$CMAKE_EGL_LIBDIR\" \"$$CMAKE_EGL_INCDIRS\") +!!ENDIF + +!!IF !isEmpty(CMAKE_OPENGL_LIBS) +_qt5gui_find_extra_libs(OPENGL \"$$CMAKE_OPENGL_LIBS\" \"$$CMAKE_OPENGL_LIBDIR\" \"$$CMAKE_OPENGL_INCDIRS\") + !!ENDIF + +!!ENDIF + +set(Qt5Gui_OPENGL_IMPLEMENTATION $$CMAKE_QT_OPENGL_IMPLEMENTATION) + +get_target_property(_configs Qt5::Gui IMPORTED_CONFIGURATIONS) +foreach(_config ${_configs}) + set_property(TARGET Qt5::Gui APPEND PROPERTY + IMPORTED_LINK_DEPENDENT_LIBRARIES_${_config} + ${Qt5Gui_EGL_LIBRARIES} ${Qt5Gui_OPENGL_LIBRARIES} + ) +endforeach() +unset(_configs) diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 339e3fbcd6..283209d08f 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -66,11 +66,8 @@ class QTextCursor; // We need to inherit QObject to expose the enums to QML. class Q_GUI_EXPORT QAccessible -#ifndef Q_QDOC - :public QObject -#endif { - Q_OBJECT + Q_GADGET Q_ENUMS(Role Event State) public: diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 9238fd91a4..062f00c4c4 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -37,18 +37,49 @@ QMAKE_LIBS += $$QMAKE_LIBS_GUI load(cmake_functions) -!contains(QT_CONFIG, angle) { +win32: CMAKE_WINDOWS_BUILD = True + +contains(QT_CONFIG, angle) { + CMAKE_GL_INCDIRS = $$CMAKE_INCLUDE_DIR + CMAKE_ANGLE_EGL_DLL_RELEASE = libEGL.dll + CMAKE_ANGLE_EGL_IMPLIB_RELEASE = libEGL.lib + CMAKE_ANGLE_GLES2_DLL_RELEASE = libGLESv2.dll + CMAKE_ANGLE_GLES2_IMPLIB_RELEASE = libGLESv2.lib + CMAKE_ANGLE_EGL_DLL_DEBUG = libEGLd.dll + CMAKE_ANGLE_EGL_IMPLIB_DEBUG = libEGLd.lib + CMAKE_ANGLE_GLES2_DLL_DEBUG = libGLESv2d.dll + CMAKE_ANGLE_GLES2_IMPLIB_DEBUG = libGLESv2d.lib + + CMAKE_QT_OPENGL_IMPLEMENTATION = GLESv2 +} else { + CMAKE_EGL_LIBS = $$cmakeProcessLibs($$QMAKE_LIBS_EGL) + !isEmpty(QMAKE_LIBDIR_EGL): CMAKE_EGL_LIBDIR += $$cmakeTargetPath($$QMAKE_LIBDIR_EGL) + contains(QT_CONFIG, opengles1) { - CMAKE_GL_INCDIRS = $$cmakeTargetPaths($$QMAKE_INCDIR_OPENGL_ES1) + !isEmpty(QMAKE_INCDIR_OPENGL_ES1): CMAKE_GL_INCDIRS = $$cmakeTargetPaths($$QMAKE_INCDIR_OPENGL_ES1) + CMAKE_OPENGL_INCDIRS = $$cmakePortablePaths($$QMAKE_INCDIR_OPENGL_ES1) + CMAKE_OPENGL_LIBS = $$cmakeProcessLibs($$QMAKE_LIBS_OPENGL_ES1) + !isEmpty(QMAKE_LIBDIR_OPENGL_ES1): CMAKE_OPENGL_LIBDIR = $$cmakePortablePaths($$QMAKE_LIBDIR_OPENGL_ES1) CMAKE_GL_HEADER_NAME = GLES/gl.h + CMAKE_QT_OPENGL_IMPLEMENTATION = GLES } else:contains(QT_CONFIG, opengles2) { - CMAKE_GL_INCDIRS = $$cmakeTargetPaths($$QMAKE_INCDIR_OPENGL_ES2) + !isEmpty(QMAKE_INCDIR_OPENGL_ES2): CMAKE_GL_INCDIRS = $$cmakeTargetPaths($$QMAKE_INCDIR_OPENGL_ES2) + CMAKE_OPENGL_INCDIRS = $$cmakePortablePaths($$QMAKE_INCDIR_OPENGL_ES2) + CMAKE_OPENGL_LIBS = $$cmakeProcessLibs($$QMAKE_LIBS_OPENGL_ES2) + !isEmpty(QMAKE_LIBDIR_OPENGL_ES2): CMAKE_OPENGL_LIBDIR = $$cmakePortablePaths($$QMAKE_LIBDIR_OPENGL_ES2) CMAKE_GL_HEADER_NAME = GLES2/gl2.h + CMAKE_QT_OPENGL_IMPLEMENTATION = GLESv2 } else { - CMAKE_GL_INCDIRS = $$cmakeTargetPaths($$QMAKE_INCDIR_OPENGL) + !isEmpty(QMAKE_INCDIR_OPENGL): CMAKE_GL_INCDIRS = $$cmakeTargetPaths($$QMAKE_INCDIR_OPENGL) + CMAKE_OPENGL_INCDIRS = $$cmakePortablePaths($$QMAKE_INCDIR_OPENGL) + CMAKE_OPENGL_LIBS = $$cmakeProcessLibs($$QMAKE_LIBS_OPENGL) + !isEmpty(QMAKE_LIBDIR_OPENGL): CMAKE_OPENGL_LIBDIR = $$cmakePortablePaths($$QMAKE_LIBDIR_OPENGL) CMAKE_GL_HEADER_NAME = GL/gl.h mac: CMAKE_GL_HEADER_NAME = gl.h + CMAKE_QT_OPENGL_IMPLEMENTATION = GL } } +CMAKE_EGL_INCDIRS = $$cmakePortablePaths($$QMAKE_INCDIR_EGL) + QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index ea35da54dc..f2f822331d 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -483,6 +483,11 @@ void QPixmapIconEngine::virtual_hook(int id, void *data) #ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QIconEngineFactoryInterface_iid, QLatin1String("/iconengines"), Qt::CaseInsensitive)) + +QFactoryLoader *qt_iconEngineFactoryLoader() +{ + return loader(); +} #endif diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index 6303f5cbe1..d202d62957 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -104,6 +104,10 @@ static inline QStringList systemIconSearchPaths() return QStringList(); } +#ifndef QT_NO_LIBRARY +extern QFactoryLoader *qt_iconEngineFactoryLoader(); // qicon.cpp +#endif + void QIconLoader::ensureInitialized() { if (!m_initialized) { @@ -116,10 +120,7 @@ void QIconLoader::ensureInitialized() if (m_systemTheme.isEmpty()) m_systemTheme = fallbackTheme(); #ifndef QT_NO_LIBRARY - QFactoryLoader iconFactoryLoader(QIconEngineFactoryInterface_iid, - QLatin1String("/iconengines"), - Qt::CaseInsensitive); - if (iconFactoryLoader.keyMap().key(QLatin1String("svg"), -1) != -1) + if (qt_iconEngineFactoryLoader()->keyMap().key(QLatin1String("svg"), -1) != -1) m_supportsSvg = true; #endif //QT_NO_LIBRARY } diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 4f1f7d838f..c5be379b7d 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -966,7 +966,7 @@ QKeyEvent::~QKeyEvent() \sa QApplication::keyboardModifiers() */ -//###### We must check with XGetModifierMapping + Qt::KeyboardModifiers QKeyEvent::modifiers() const { if (key() == Qt::Key_Shift) @@ -977,6 +977,8 @@ Qt::KeyboardModifiers QKeyEvent::modifiers() const return Qt::KeyboardModifiers(QInputEvent::modifiers()^Qt::AltModifier); if (key() == Qt::Key_Meta) return Qt::KeyboardModifiers(QInputEvent::modifiers()^Qt::MetaModifier); + if (key() == Qt::Key_AltGr) + return Qt::KeyboardModifiers(QInputEvent::modifiers()^Qt::GroupSwitchModifier); return QInputEvent::modifiers(); } @@ -990,10 +992,10 @@ Qt::KeyboardModifiers QKeyEvent::modifiers() const */ bool QKeyEvent::matches(QKeySequence::StandardKey matchKey) const { - uint searchkey = (modifiers() | key()) & ~(Qt::KeypadModifier); //The keypad modifier should not make a difference + //The keypad and group switch modifier should not make a difference + uint searchkey = (modifiers() | key()) & ~(Qt::KeypadModifier | Qt::GroupSwitchModifier); const uint platform = QKeySequencePrivate::currentKeyPlatforms(); - uint N = QKeySequencePrivate::numberOfKeyBindings; int first = 0; int last = N - 1; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index fba516c135..3c79e62e75 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1640,6 +1640,10 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate } emit qApp->focusWindowChanged(newFocus); + if (previous) + emit previous->activeChanged(); + if (newFocus) + emit newFocus->activeChanged(); } void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *wse) @@ -1736,6 +1740,9 @@ void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::Cl QCloseEvent event; QGuiApplication::sendSpontaneousEvent(e->window.data(), &event); + if (e->accepted) { + *(e->accepted) = !event.isAccepted(); + } } void QGuiApplicationPrivate::processFileOpenEvent(QWindowSystemInterfacePrivate::FileOpenEvent *e) diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 44de8c5847..a0255f610a 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -1225,7 +1225,8 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence *gmodifs << QModifKeyName(Qt::CTRL, QLatin1String("ctrl+")) << QModifKeyName(Qt::SHIFT, QLatin1String("shift+")) << QModifKeyName(Qt::ALT, QLatin1String("alt+")) - << QModifKeyName(Qt::META, QLatin1String("meta+")); + << QModifKeyName(Qt::META, QLatin1String("meta+")) + << QModifKeyName(Qt::KeypadModifier, QLatin1String("numpad+")); } } else { gmodifs = globalPortableModifs(); @@ -1233,7 +1234,8 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence *gmodifs << QModifKeyName(Qt::CTRL, QLatin1String("ctrl+")) << QModifKeyName(Qt::SHIFT, QLatin1String("shift+")) << QModifKeyName(Qt::ALT, QLatin1String("alt+")) - << QModifKeyName(Qt::META, QLatin1String("meta+")); + << QModifKeyName(Qt::META, QLatin1String("meta+")) + << QModifKeyName(Qt::KeypadModifier, QLatin1String("numpad+")); } } if (!gmodifs) return ret; @@ -1244,7 +1246,8 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence modifs << QModifKeyName(Qt::CTRL, QCoreApplication::translate("QShortcut", "Ctrl").toLower().append(QLatin1Char('+'))) << QModifKeyName(Qt::SHIFT, QCoreApplication::translate("QShortcut", "Shift").toLower().append(QLatin1Char('+'))) << QModifKeyName(Qt::ALT, QCoreApplication::translate("QShortcut", "Alt").toLower().append(QLatin1Char('+'))) - << QModifKeyName(Qt::META, QCoreApplication::translate("QShortcut", "Meta").toLower().append(QLatin1Char('+'))); + << QModifKeyName(Qt::META, QCoreApplication::translate("QShortcut", "Meta").toLower().append(QLatin1Char('+'))) + << QModifKeyName(Qt::KeypadModifier, QCoreApplication::translate("QShortcut", "Numpad").toLower().append(QLatin1Char('+'))); } modifs += *gmodifs; // Test non-translated ones last @@ -1418,10 +1421,12 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Alt") : QString::fromLatin1("Alt"), format); if ((key & Qt::SHIFT) == Qt::SHIFT) addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Shift") : QString::fromLatin1("Shift"), format); + if ((key & Qt::KeypadModifier) == Qt::KeypadModifier) + addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Numpad") : QString::fromLatin1("Numpad"), format); } - key &= ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier); + key &= ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier); QString p; if (key && key < Qt::Key_Escape && key != Qt::Key_Space) { diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 483baf0f09..c93752c3d7 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -759,7 +759,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface) return false; if (surface->surfaceType() != QSurface::OpenGLSurface) { - qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface"; + qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface; return false; } diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 8c9bc575bd..0dd85f2d56 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -874,6 +874,14 @@ bool QWindow::isExposed() const } /*! + \property QWindow::active + \brief the active status of the window + \since 5.1 + + \sa requestActivate() +*/ + +/*! Returns true if the window should appear active from a style perspective. This is the case for the window that has input focus as well as windows diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index 9b1ed2c702..79f90f2c62 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -115,6 +115,7 @@ class Q_GUI_EXPORT QWindow : public QObject, public QSurface Q_PROPERTY(int maximumWidth READ maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged REVISION 1) Q_PROPERTY(int maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged REVISION 1) Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged) + Q_PROPERTY(bool active READ isActive NOTIFY activeChanged REVISION 1) Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged REVISION 1) Q_PROPERTY(Qt::ScreenOrientation contentOrientation READ contentOrientation WRITE reportContentOrientationChange NOTIFY contentOrientationChanged REVISION 1) Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged REVISION 1) @@ -170,8 +171,6 @@ public: void setMask(const QRegion ®ion); QRegion mask() const; - void requestActivate(); - bool isActive() const; void reportContentOrientationChange(Qt::ScreenOrientation orientation); @@ -264,6 +263,8 @@ public: static QWindow *fromWinId(WId id); public Q_SLOTS: + Q_REVISION(1) void requestActivate(); + void setVisible(bool visible); void show(); @@ -310,6 +311,7 @@ Q_SIGNALS: void visibleChanged(bool arg); Q_REVISION(1) void visibilityChanged(QWindow::Visibility visibility); + Q_REVISION(1) void activeChanged(); Q_REVISION(1) void contentOrientationChanged(Qt::ScreenOrientation orientation); void focusObjectChanged(QObject *object); diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index d2add91d66..7dc1e7f7e5 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -140,11 +140,11 @@ void QWindowSystemInterface::handleGeometryChange(QWindow *tlw, const QRect &new QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } -void QWindowSystemInterface::handleCloseEvent(QWindow *tlw) +void QWindowSystemInterface::handleCloseEvent(QWindow *tlw, bool *accepted) { if (tlw) { QWindowSystemInterfacePrivate::CloseEvent *e = - new QWindowSystemInterfacePrivate::CloseEvent(tlw); + new QWindowSystemInterfacePrivate::CloseEvent(tlw, accepted); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } } diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 212259c113..521c2a4941 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -131,7 +131,7 @@ public: static void handleTouchCancelEvent(QWindow *w, ulong timestamp, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier); static void handleGeometryChange(QWindow *w, const QRect &newRect); - static void handleCloseEvent(QWindow *w); + static void handleCloseEvent(QWindow *w, bool *accepted = 0); static void handleEnterEvent(QWindow *w, const QPointF &local = QPointF(), const QPointF& global = QPointF()); static void handleLeaveEvent(QWindow *w); static void handleEnterLeaveEvent(QWindow *enter, QWindow *leave, const QPointF &local = QPointF(), const QPointF& global = QPointF()); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index f1bc4667f7..a6ea15c5f2 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -105,9 +105,11 @@ public: class CloseEvent : public WindowSystemEvent { public: - explicit CloseEvent(QWindow *w) - : WindowSystemEvent(Close), window(w) { } + explicit CloseEvent(QWindow *w, bool *a = 0) + : WindowSystemEvent(Close), window(w), accepted(a) + { } QPointer<QWindow> window; + bool *accepted; }; class GeometryChangeEvent : public WindowSystemEvent { diff --git a/src/gui/opengl/qopengltimerquery.h b/src/gui/opengl/qopengltimerquery.h index 649e80d6c0..c1cada9bdb 100644 --- a/src/gui/opengl/qopengltimerquery.h +++ b/src/gui/opengl/qopengltimerquery.h @@ -42,6 +42,8 @@ #ifndef QOPENGLTIMERQUERY_H #define QOPENGLTIMERQUERY_H +#include <QtCore/qglobal.h> + #if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) #include <QtCore/QObject> diff --git a/src/gui/opengl/qopenglvertexarrayobject.h b/src/gui/opengl/qopenglvertexarrayobject.h index d5226d3ebd..569aeea730 100644 --- a/src/gui/opengl/qopenglvertexarrayobject.h +++ b/src/gui/opengl/qopenglvertexarrayobject.h @@ -42,6 +42,8 @@ #ifndef QOPENGLVERTEXARRAYOBJECT_H #define QOPENGLVERTEXARRAYOBJECT_H +#include <QtCore/qglobal.h> + #ifndef QT_NO_OPENGL #include <QtCore/QObject> diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index fac83b922b..04daf2ecdd 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -92,7 +92,7 @@ static res_state_ptr local_res = 0; static void resolveLibrary() { -#ifndef QT_NO_LIBRARY +#if !defined(QT_NO_LIBRARY) && !defined(Q_OS_QNX) QLibrary lib(QLatin1String("resolv")); if (!lib.load()) return; diff --git a/src/network/kernel/qnetworkproxy_generic.cpp b/src/network/kernel/qnetworkproxy_generic.cpp index 9069755da4..c576719076 100644 --- a/src/network/kernel/qnetworkproxy_generic.cpp +++ b/src/network/kernel/qnetworkproxy_generic.cpp @@ -55,7 +55,11 @@ QT_BEGIN_NAMESPACE static bool ignoreProxyFor(const QNetworkProxyQuery &query) { - const QList<QByteArray> noProxyTokens = qgetenv("no_proxy").split(','); + const QByteArray noProxy = qgetenv("no_proxy").trimmed(); + if (noProxy.isEmpty()) + return false; + + const QList<QByteArray> noProxyTokens = noProxy.split(','); foreach (const QByteArray &rawToken, noProxyTokens) { QByteArray token = rawToken.trimmed(); diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index a8bf8f83b8..f2310356df 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -1908,6 +1908,7 @@ QSslSocketPrivate::QSslSocketPrivate() , mode(QSslSocket::UnencryptedMode) , autoStartHandshake(false) , connectionEncrypted(false) + , shutdown(false) , ignoreAllSslErrors(false) , readyReadEmittedPointer(0) , allowRootCertOnDemandLoading(true) @@ -1933,6 +1934,7 @@ void QSslSocketPrivate::init() autoStartHandshake = false; connectionEncrypted = false; ignoreAllSslErrors = false; + shutdown = false; // we don't want to clear the ignoreErrorsList, so // that it is possible setting it before connecting diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 0ce5c8915d..24428a0321 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -934,8 +934,11 @@ void QSslSocketBackendPrivate::transmit() #ifdef QSSLSOCKET_DEBUG qDebug() << "QSslSocketBackendPrivate::transmit: remote disconnect"; #endif - plainSocket->disconnectFromHost(); - break; + shutdown = true; // the other side shut down, make sure we do not send shutdown ourselves + q->setErrorString(QSslSocket::tr("The TLS/SSL connection has been closed")); + q->setSocketError(QAbstractSocket::RemoteHostClosedError); + emit q->error(QAbstractSocket::RemoteHostClosedError); + return; case SSL_ERROR_SYSCALL: // some IO error case SSL_ERROR_SSL: // error in the SSL library // we do not know exactly what the error is, nor whether we can recover from it, @@ -1369,8 +1372,11 @@ void QWindowsCaRootFetcher::start() void QSslSocketBackendPrivate::disconnectFromHost() { if (ssl) { - q_SSL_shutdown(ssl); - transmit(); + if (!shutdown) { + q_SSL_shutdown(ssl); + shutdown = true; + transmit(); + } } plainSocket->disconnectFromHost(); } diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 72117353ac..d1d79ae09c 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -109,6 +109,7 @@ public: QSslSocket::SslMode mode; bool autoStartHandshake; bool connectionEncrypted; + bool shutdown; bool ignoreAllSslErrors; QList<QSslError> ignoreErrorsList; bool* readyReadEmittedPointer; diff --git a/src/opengl/doc/qtopengl.qdocconf b/src/opengl/doc/qtopengl.qdocconf index d0f49fd602..eea618d8ea 100644 --- a/src/opengl/doc/qtopengl.qdocconf +++ b/src/opengl/doc/qtopengl.qdocconf @@ -1,7 +1,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) # Name of the project which must match the outputdir. Determines the .index file -project = qtopengl +project = QtOpenGL # Directories in which to search for files to document and images. # By default set to the root directory of the project for sources @@ -32,23 +32,23 @@ examplesinstallpath = opengl # Defines the name of the project. You cannot use operators (+, =, -) in # the name. Properties for this project are set using a qhp.<projectname>.property # format. -qhp.projects = qtopengl +qhp.projects = QtOpenGL # Sets the name of the output qhp file. -qhp.qtopengl.file = qtopengl.qhp +qhp.QtOpenGL.file = qtopengl.qhp # Namespace for the output file. This namespace is used to distinguish between # different documentation files in Creator/Assistant. -qhp.qtopengl.namespace = org.qt-project.qtopengl.$QT_VERSION_TAG +qhp.QtOpenGL.namespace = org.qt-project.qtopengl.$QT_VERSION_TAG # Title for the package, will be the main title for the package in # Assistant/Creator. -qhp.qtopengl.indexTitle = Qt OpenGL +qhp.QtOpenGL.indexTitle = Qt OpenGL # Only update the name of the project for the next variables. -qhp.qtopengl.virtualFolder = qtopengl -qhp.qtopengl.subprojects = classes -qhp.qtopengl.subprojects.classes.title = C++ Classes -qhp.qtopengl.subprojects.classes.indexTitle = Qt OpenGL C++ Classes -qhp.qtopengl.subprojects.classes.selectors = class fake:headerfile -qhp.qtopengl.subprojects.classes.sortPages = true +qhp.QtOpenGL.virtualFolder = qtopengl +qhp.QtOpenGL.subprojects = classes +qhp.QtOpenGL.subprojects.classes.title = C++ Classes +qhp.QtOpenGL.subprojects.classes.indexTitle = Qt OpenGL C++ Classes +qhp.QtOpenGL.subprojects.classes.selectors = class fake:headerfile +qhp.QtOpenGL.subprojects.classes.sortPages = true diff --git a/src/opengl/qgl_qpa.cpp b/src/opengl/qgl_qpa.cpp index 0a24654624..f3388ee5ef 100644 --- a/src/opengl/qgl_qpa.cpp +++ b/src/opengl/qgl_qpa.cpp @@ -146,10 +146,15 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) if (widget->testAttribute(Qt::WA_TranslucentBackground)) winFormat.setAlphaBufferSize(qMax(winFormat.alphaBufferSize(), 8)); - if (!widget->windowHandle()->handle()) { - widget->windowHandle()->setSurfaceType(QWindow::OpenGLSurface); - widget->windowHandle()->setFormat(winFormat); - widget->winId();//make window + QWindow *window = widget->windowHandle(); + if (!window->handle() + || window->surfaceType() != QWindow::OpenGLSurface + || window->requestedFormat() != winFormat) + { + window->setSurfaceType(QWindow::OpenGLSurface); + window->setFormat(winFormat); + window->destroy(); + window->create(); } if (d->ownContext) diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index 9c28c9fa63..91472f9efb 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -47,11 +47,17 @@ #include <QtCore/QElapsedTimer> +#include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformscreen.h> +#include <qpa/qplatformintegration.h> +#include <qpa/qplatformservices.h> #include <QtGui/private/qfontengine_ft_p.h> #include <QtGui/private/qfontengine_p.h> #include <QtGui/private/qfontengine_qpa_p.h> +#include <QtGui/private/qguiapplication_p.h> + +#include <QtGui/qguiapplication.h> #include <ft2build.h> #include FT_TRUETYPE_TABLES_H @@ -640,6 +646,19 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script sc break; } } + + if (f.hintingPreference == QFont::PreferDefaultHinting) { + QByteArray desktopEnvironment = QGuiApplicationPrivate::platformIntegration()->services()->desktopEnvironment(); + if (desktopEnvironment == "GNOME" || desktopEnvironment == "UNITY") { + void *hintStyleResource = + QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle", + QGuiApplication::primaryScreen()); + int hintStyle = int(reinterpret_cast<qintptr>(hintStyleResource)); + if (hintStyle > 0) + default_hint_style = QFontEngine::HintStyle(hintStyle - 1); + } + } + engine->setDefaultHintStyle(default_hint_style); if (antialias) { diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp index 9719319b03..26dc116f91 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp @@ -104,6 +104,7 @@ QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, cons int repeatRate = 80; bool disableZap = false; bool enableCompose = false; + int grab = 0; QStringList args = specification.split(QLatin1Char(':')); foreach (const QString &arg, args) { @@ -117,6 +118,8 @@ QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, cons repeatDelay = arg.mid(13).toInt(); else if (arg.startsWith(QLatin1String("repeat-rate="))) repeatRate = arg.mid(12).toInt(); + else if (arg.startsWith(QLatin1String("grab="))) + grab = arg.mid(5).toInt(); } #ifdef QT_QPA_KEYMAP_DEBUG @@ -126,6 +129,7 @@ QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device, cons int fd; fd = qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); if (fd >= 0) { + ::ioctl(fd, EVIOCGRAB, grab); if (repeatDelay > 0 && repeatRate > 0) { int kbdrep[2] = { repeatDelay, repeatRate }; ::ioctl(fd, EVIOCSREP, kbdrep); diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index 27c5f18d1a..92f807095f 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -70,6 +70,7 @@ QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QStr bool compression = true; int jitterLimit = 0; + int grab = 0; QStringList args = specification.split(QLatin1Char(':')); foreach (const QString &arg, args) { @@ -77,11 +78,14 @@ QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QStr compression = false; else if (arg.startsWith(QLatin1String("dejitter="))) jitterLimit = arg.mid(9).toInt(); + else if (arg.startsWith(QLatin1String("grab="))) + grab = arg.mid(5).toInt(); } int fd; fd = qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); if (fd >= 0) { + ::ioctl(fd, EVIOCGRAB, grab); return new QEvdevMouseHandler(device, fd, compression, jitterLimit); } else { qWarning("Cannot open mouse input device '%s': %s", qPrintable(device), strerror(errno)); diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp index 4ddd39f7ea..d460ec2c98 100644 --- a/src/plugins/accessible/widgets/itemviews.cpp +++ b/src/plugins/accessible/widgets/itemviews.cpp @@ -120,6 +120,8 @@ QHeaderView *QAccessibleTable::horizontalHeader() const #ifndef QT_NO_TREEVIEW } else if (const QTreeView *tv = qobject_cast<const QTreeView*>(view())) { header = tv->header(); + if (header && header->isHidden()) + header = 0; #endif } return header; @@ -766,7 +768,6 @@ int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const int column = cell->m_index.column(); int index = row * view()->model()->columnCount() + column; - Q_ASSERT(index >= treeView->model()->columnCount()); return index; } else if (iface->role() == QAccessible::ColumnHeader){ const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface); diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.cpp b/src/plugins/accessible/widgets/qaccessiblemenu.cpp index f248e6d05e..39ac335131 100644 --- a/src/plugins/accessible/widgets/qaccessiblemenu.cpp +++ b/src/plugins/accessible/widgets/qaccessiblemenu.cpp @@ -206,7 +206,7 @@ int QAccessibleMenuItem::indexOfChild(const QAccessibleInterface * child) const bool QAccessibleMenuItem::isValid() const { - return m_action ? true : false; + return m_action && m_owner ? true : false; } QAccessibleInterface *QAccessibleMenuItem::parent() const diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.h b/src/plugins/accessible/widgets/qaccessiblemenu.h index 74d118a09e..f933a4a37e 100644 --- a/src/plugins/accessible/widgets/qaccessiblemenu.h +++ b/src/plugins/accessible/widgets/qaccessiblemenu.h @@ -43,6 +43,7 @@ #define QACCESSIBLEMENU_H #include <QtWidgets/private/qaccessiblewidget_p.h> +#include <QtCore/qpointer.h> QT_BEGIN_NAMESPACE @@ -120,7 +121,7 @@ protected: QAction *action() const; private: QAction *m_action; - QWidget *m_owner; // can hold either QMenu or the QMenuBar that contains the action + QPointer<QWidget> m_owner; // can hold either QMenu or the QMenuBar that contains the action }; #endif // QT_NO_MENU diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp index f20823f25b..59dc03666b 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -1127,7 +1127,7 @@ QAccessibleMainWindow::QAccessibleMainWindow(QWidget *widget) QAccessibleInterface *QAccessibleMainWindow::child(int index) const { QList<QWidget*> kids = childWidgets(mainWindow(), true); - if (index < kids.count()) { + if (index >= 0 && index < kids.count()) { return QAccessible::queryAccessibleInterface(kids.at(index)); } return 0; diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index 1113194136..400f7aece8 100644 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -280,8 +280,7 @@ ushort TableGenerator::keysymToUtf8(quint32 sym) qDebug() << QString("keysym - 0x%1 : utf8 - %2").arg(QString::number(sym, 16)) .arg(codec->toUnicode(chars)); #endif - const QChar *ch = QString(chars.data()).unicode(); - return ch->unicode(); + return QString::fromUtf8(chars).at(0).unicode(); } quint32 TableGenerator::stringToKeysym(QString keysymName) diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp index 3de6c47ad0..f0630b5224 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp @@ -183,7 +183,6 @@ QAndroidPlatformIntegration::~QAndroidPlatformIntegration() { delete m_androidPlatformNativeInterface; delete m_androidFDB; - delete m_touchDevice; QtAndroid::setAndroidPlatformIntegration(NULL); } QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 66c4e3c49c..a2fd8c0613 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -41,6 +41,8 @@ OBJECTIVE_SOURCES += main.mm \ qcocoaintrospection.mm \ qcocoakeymapper.mm \ +SOURCES += messages.cpp + HEADERS += qcocoaintegration.h \ qcocoatheme.h \ qcocoabackingstore.h \ @@ -75,6 +77,7 @@ HEADERS += qcocoaintegration.h \ qcocoasystemtrayicon.h \ qcocoaintrospection.h \ qcocoakeymapper.h \ + messages.h RESOURCES += qcocoaresources.qrc diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp new file mode 100644 index 0000000000..3db1618a50 --- /dev/null +++ b/src/plugins/platforms/cocoa/messages.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "messages.h" + +#include <QCoreApplication> + +// Translatable messages should go into this .cpp file for them to be picked up by lupdate. + +QT_BEGIN_NAMESPACE + +QString msgAboutQt() +{ + return QCoreApplication::translate("QCocoaMenuItem", "About Qt"); +} + +static const char *application_menu_strings[] = +{ + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"), + QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1") +}; + +QString qt_mac_applicationmenu_string(int type) +{ + QString menuString = QString::fromLatin1(application_menu_strings[type]); + const QString translated = QCoreApplication::translate("QMenuBar", application_menu_strings[type]); + if (translated != menuString) { + return translated; + } else { + return QCoreApplication::translate("MAC_APPLICATION_MENU", application_menu_strings[type]); + } +} + +QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption) +{ + const QString aboutString = QCoreApplication::translate("QCocoaMenuItem", "About"); + if (caption.startsWith(aboutString, Qt::CaseInsensitive) || caption.endsWith(aboutString, Qt::CaseInsensitive)) + return QPlatformMenuItem::AboutRole; + if (caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Config"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Preference"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Options"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Setting"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Setup"), Qt::CaseInsensitive)) { + return QPlatformMenuItem::PreferencesRole; + } + if (caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Quit"), Qt::CaseInsensitive) + || caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Exit"), Qt::CaseInsensitive)) { + return QPlatformMenuItem::QuitRole; + } + return QPlatformMenuItem::NoRole; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/messages.h b/src/plugins/platforms/cocoa/messages.h new file mode 100644 index 0000000000..09705c1e21 --- /dev/null +++ b/src/plugins/platforms/cocoa/messages.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MESSAGES_H +#define MESSAGES_H + +#include <QString> +#include <qpa/qplatformmenu.h> + +QT_BEGIN_NAMESPACE + +QString msgAboutQt(); + +QString qt_mac_applicationmenu_string(int type); + +QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption); + +QT_END_NAMESPACE + +#endif // MESSAGES_H diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 25780e79f4..9c38a874e5 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -165,8 +165,11 @@ NSString *macRole(QAccessibleInterface *interface) return roleMap[qtRole]; } - // MAC_ACCESSIBILTY_DEBUG() << "return NSAccessibilityUnknownRole"; - return NSAccessibilityUnknownRole; + // Treat unknown Qt roles as generic group container items. Returning + // NSAccessibilityUnknownRole is also possible but makes the screen + // reader focus on the item instead of passing focus to child items. + // MAC_ACCESSIBILTY_DEBUG() << "return NSAccessibilityGroupRole for unknown Qt role"; + return NSAccessibilityGroupRole; } /* diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index 12808b7041..e5b41e7a88 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -199,14 +199,14 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor) #endif const uchar *cursorData = 0; const uchar *cursorMaskData = 0; - QPoint hotspot; + QPoint hotspot = cursor->hotSpot(); switch (cursor->shape()) { case Qt::BitmapCursor: { if (cursor->pixmap().isNull()) - return createCursorFromBitmap(cursor->bitmap(), cursor->mask()); + return createCursorFromBitmap(cursor->bitmap(), cursor->mask(), hotspot); else - return createCursorFromPixmap(cursor->pixmap()); + return createCursorFromPixmap(cursor->pixmap(), hotspot); break; } case Qt::BlankCursor: { QPixmap pixmap = QPixmap(16, 16); @@ -215,19 +215,19 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor) break; } case Qt::WaitCursor: { QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/spincursor.png")); - return createCursorFromPixmap(pixmap); + return createCursorFromPixmap(pixmap, hotspot); break; } case Qt::SizeAllCursor: { QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/pluscursor.png")); - return createCursorFromPixmap(pixmap); + return createCursorFromPixmap(pixmap, hotspot); break; } case Qt::BusyCursor: { QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/waitcursor.png")); - return createCursorFromPixmap(pixmap); + return createCursorFromPixmap(pixmap, hotspot); break; } case Qt::ForbiddenCursor: { QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/forbiddencursor.png")); - return createCursorFromPixmap(pixmap); + return createCursorFromPixmap(pixmap, hotspot); break; } #define QT_USE_APPROXIMATE_CURSORS #ifdef QT_USE_APPROXIMATE_CURSORS diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 439b7f1a75..9100b9b15f 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -47,10 +47,6 @@ #include <qpa/qplatformmenu.h> #include "qcocoamenuitem.h" -@class NSMenuItem; -@class NSMenu; -@class NSObject; - QT_BEGIN_NAMESPACE class QCocoaMenu : public QPlatformMenu @@ -81,8 +77,6 @@ public: void setMinimumWidth(int width); void setFont(const QFont &font); - void setParentItem(QCocoaMenuItem* item); - inline NSMenu *nsMenu() const { return m_nativeMenu; } inline NSMenuItem *nsMenuItem() const @@ -91,6 +85,7 @@ public: virtual QPlatformMenuItem *menuItemAt(int position) const; virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const; + QList<QCocoaMenuItem *> items() const; QList<QCocoaMenuItem *> merged() const; private: QCocoaMenuItem *itemOrNull(int index) const; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index bde9ded14f..c5c5c132bc 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -45,11 +45,34 @@ #include "qcocoaautoreleasepool.h" #include <QtCore/QtDebug> +#include <QtCore/private/qthread_p.h> +#include <QtGui/private/qguiapplication_p.h> #include "qcocoaapplication.h" #include "qcocoamenuloader.h" #include "qcocoawindow.h" #import "qnsview.h" +NSString *qt_mac_removePrivateUnicode(NSString* string) +{ + int len = [string length]; + if (len) { + QVarLengthArray <unichar, 10> characters(len); + bool changed = false; + for (int i = 0; i<len; i++) { + characters[i] = [string characterAtIndex:i]; + // check if they belong to key codes in private unicode range + // currently we need to handle only the NSDeleteFunctionKey + if (characters[i] == NSDeleteFunctionKey) { + characters[i] = NSDeleteCharacter; + changed = true; + } + } + if (changed) + return [NSString stringWithCharacters:characters.data() length:len]; + } + return string; +} + static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() { return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)]; @@ -89,6 +112,7 @@ static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() - (void) itemFired:(NSMenuItem*) item { QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]); + QScopedLoopLevelCounter loopLevelCounter(QGuiApplicationPrivate::instance()->threadData); cocoaItem->activated(); } @@ -101,6 +125,80 @@ static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader() return cocoaItem->isEnabled(); } +- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action +{ + /* + Check if the menu actually has a keysequence defined for this key event. + If it does, then we will first send the key sequence to the QWidget that has focus + since (in Qt's eyes) it needs to a chance at the key event first (QEvent::ShortcutOverride). + If the widget accepts the key event, we then return YES, but set the target and action to be nil, + which means that the action should not be triggered, and instead dispatch the event ourselves. + In every other case we return NO, which means that Cocoa can do as it pleases + (i.e., fire the menu action). + */ + + // Change the private unicode keys to the ones used in setting the "Key Equivalents" + NSString *characters = qt_mac_removePrivateUnicode([event characters]); + if ([self hasShortcut:menu + forKey:characters + // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ... + forModifiers:([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask)) + ]) { + QObject *object = qApp->focusObject(); + if (object) { + QChar ch; + int keyCode; + ulong nativeModifiers = [event modifierFlags]; + Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers]; + NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers]; + NSString *characters = [event characters]; + + if ([charactersIgnoringModifiers length] > 0) { // convert the first character into a key code + if ((modifiers & Qt::ControlModifier) && ([characters length] != 0)) { + ch = QChar([characters characterAtIndex:0]); + } else { + ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); + } + keyCode = qt_mac_cocoaKey2QtKey(ch); + } else { + // might be a dead key + ch = QChar::ReplacementCharacter; + keyCode = Qt::Key_unknown; + } + + QKeyEvent accel_ev(QEvent::ShortcutOverride, (keyCode & (~Qt::KeyboardModifierMask)), + Qt::KeyboardModifiers(keyCode & Qt::KeyboardModifierMask)); + accel_ev.ignore(); + QCoreApplication::sendEvent(object, &accel_ev); + if (accel_ev.isAccepted()) { + [[NSApp keyWindow] sendEvent: event]; + *target = nil; + *action = nil; + return YES; + } + } + } + return NO; +} + +- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier +{ + for (NSMenuItem *item in [menu itemArray]) { + if (![item isEnabled] || [item isHidden] || [item isSeparatorItem]) + continue; + if ([item hasSubmenu] + && [self hasShortcut:[item submenu] forKey:key forModifiers:modifier]) + return YES; + + NSString *menuKey = [item keyEquivalent]; + if (menuKey + && NSOrderedSame == [menuKey compare:key] + && modifier == [item keyEquivalentModifierMask]) + return YES; + } + return NO; +} + @end QT_BEGIN_NAMESPACE @@ -154,6 +252,7 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem * QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem); QCocoaMenuItem *beforeItem = static_cast<QCocoaMenuItem *>(before); + menuItem->setParent(this); cocoaItem->sync(); if (beforeItem) { int index = m_menuItems.indexOf(beforeItem); @@ -209,6 +308,10 @@ void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem) qWarning() << Q_FUNC_INFO << "Menu does not contain the item to be removed"; return; } + + if (menuItem->parent() == this) + menuItem->setParent(0); + m_menuItems.removeOne(cocoaItem); if (!cocoaItem->isMerged()) { if (m_nativeMenu != [cocoaItem->nsItem() menu]) { @@ -266,8 +369,12 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable) NSArray *itemArray = [m_nativeMenu itemArray]; for (unsigned int i = 0; i < [itemArray count]; ++i) { NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]); - if ([item isSeparatorItem]) + if ([item isSeparatorItem]) { + QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]); + if (cocoaItem) + cocoaItem->setVisible(!previousIsSeparator); [item setHidden:previousIsSeparator]; + } if (![item isHidden]) { previousItem = item; @@ -276,8 +383,12 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable) } // We now need to check the final item since we don't want any separators at the end of the list. - if (previousItem && previousIsSeparator) + if (previousItem && previousIsSeparator) { + QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([previousItem tag]); + if (cocoaItem) + cocoaItem->setVisible(false); [previousItem setHidden:YES]; + } } else { foreach (QCocoaMenuItem *item, m_menuItems) { if (!item->isSeparator()) @@ -289,11 +400,6 @@ void QCocoaMenu::syncSeparatorsCollapsible(bool enable) } } -void QCocoaMenu::setParentItem(QCocoaMenuItem *item) -{ - Q_UNUSED(item); -} - void QCocoaMenu::setEnabled(bool enabled) { m_enabled = enabled; @@ -378,6 +484,11 @@ QPlatformMenuItem *QCocoaMenu::menuItemForTag(quintptr tag) const return 0; } +QList<QCocoaMenuItem *> QCocoaMenu::items() const +{ + return m_menuItems; +} + QList<QCocoaMenuItem *> QCocoaMenu::merged() const { QList<QCocoaMenuItem *> result; diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h index 2db2abcaaf..8086676cc5 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.h +++ b/src/plugins/platforms/cocoa/qcocoamenubar.h @@ -47,14 +47,13 @@ #include <qpa/qplatformmenu.h> #include "qcocoamenu.h" -@class NSMenu; - QT_BEGIN_NAMESPACE class QCocoaWindow; class QCocoaMenuBar : public QPlatformMenuBar { + Q_OBJECT public: QCocoaMenuBar(); virtual ~QCocoaMenuBar(); diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index b880db16a2..b112e40549 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -109,6 +109,8 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor [m_nativeMenu addItem: menu->nsMenuItem()]; } + platformMenu->setParent(this); + syncMenu(platformMenu); [m_nativeMenu setSubmenu: menu->nsMenu() forItem: menu->nsMenuItem()]; } @@ -123,13 +125,17 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu) } m_menus.removeOne(menu); + if (platformMenu->parent() == this) + platformMenu->setParent(0); NSUInteger realIndex = [m_nativeMenu indexOfItem:menu->nsMenuItem()]; [m_nativeMenu removeItemAtIndex: realIndex]; } void QCocoaMenuBar::syncMenu(QPlatformMenu *menu) { - Q_UNUSED(menu); + QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(menu); + Q_FOREACH (QCocoaMenuItem *item, cocoaMenu->items()) + cocoaMenu->syncMenuItem(item); } void QCocoaMenuBar::handleReparent(QWindow *newParentWindow) diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index 0e6d17343d..1e69ed5a4b 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -48,8 +48,16 @@ //#define QT_COCOA_ENABLE_MENU_DEBUG -@class NSMenuItem; -@class NSMenu; +#ifdef __OBJC__ +#define QT_FORWARD_DECLARE_OBJC_CLASS(__KLASS__) @class __KLASS__ +#else +#define QT_FORWARD_DECLARE_OBJC_CLASS(__KLASS__) typedef struct objc_object __KLASS__ +#endif + +QT_FORWARD_DECLARE_OBJC_CLASS(NSMenuItem); +QT_FORWARD_DECLARE_OBJC_CLASS(NSMenu); +QT_FORWARD_DECLARE_OBJC_CLASS(NSObject); + QT_BEGIN_NAMESPACE @@ -96,6 +104,7 @@ private: NSMenuItem *m_native; QString m_text; + bool m_textSynced; QIcon m_icon; QCocoaMenu *m_menu; bool m_isVisible; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 350ef8a16a..1255f75eb7 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -42,6 +42,8 @@ #include "qcocoamenuitem.h" #include "qcocoamenu.h" +#include "qcocoamenubar.h" +#include "messages.h" #include "qcocoahelpers.h" #include "qcocoaautoreleasepool.h" #include "qt_mac_p.h" @@ -89,6 +91,7 @@ NSUInteger keySequenceModifierMask(const QKeySequence &accel) QCocoaMenuItem::QCocoaMenuItem() : m_native(NULL), + m_textSynced(false), m_menu(NULL), m_isVisible(true), m_enabled(true), @@ -123,11 +126,13 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) { if (menu == m_menu) return; + if (m_menu && m_menu->parent() == this) + m_menu->setParent(0); QCocoaAutoReleasePool pool; m_menu = static_cast<QCocoaMenu *>(menu); if (m_menu) { - m_menu->setParentItem(this); + m_menu->setParent(this); } else { // we previously had a menu, but no longer // clear out our item so the nexy sync() call builds a new one @@ -153,6 +158,8 @@ void QCocoaMenuItem::setFont(const QFont &font) void QCocoaMenuItem::setRole(MenuRole role) { + if (role != m_role) + m_textSynced = false; // Changing role deserves a second chance. m_role = role; } @@ -190,7 +197,7 @@ NSMenuItem *QCocoaMenuItem::sync() } } - if ((m_role != NoRole) || m_merged) { + if ((m_role != NoRole && !m_textSynced) || m_merged) { NSMenuItem *mergeItem = nil; QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader(); switch (m_role) { @@ -210,25 +217,33 @@ NSMenuItem *QCocoaMenuItem::sync() mergeItem = [loader preferencesMenuItem]; break; case TextHeuristicRole: { - QString aboutString = tr("About").toLower(); - if (m_text.startsWith(aboutString, Qt::CaseInsensitive) - || m_text.endsWith(aboutString, Qt::CaseInsensitive)) - { + QObject *p = parent(); + int depth = 1; + QCocoaMenuBar *menubar = 0; + while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) { + ++depth; + p = p->parent(); + } + if (depth == 3 || !menubar) + break; // Menu item too deep in the hierarchy, or not connected to any menubar + + switch (detectMenuRole(m_text)) { + case QPlatformMenuItem::AboutRole: if (m_text.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1) mergeItem = [loader aboutMenuItem]; else mergeItem = [loader aboutQtMenuItem]; - } else if (m_text.startsWith(tr("Config"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Preference"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Options"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Setting"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Setup"), Qt::CaseInsensitive)) { + break; + case QPlatformMenuItem::PreferencesRole: mergeItem = [loader preferencesMenuItem]; - } else if (m_text.startsWith(tr("Quit"), Qt::CaseInsensitive) - || m_text.startsWith(tr("Exit"), Qt::CaseInsensitive)) { + break; + case QPlatformMenuItem::QuitRole: mergeItem = [loader quitMenuItem]; + break; + default: + m_textSynced = true; + break; } - break; } @@ -237,6 +252,7 @@ NSMenuItem *QCocoaMenuItem::sync() } if (mergeItem) { + m_textSynced = true; m_merged = true; [mergeItem retain]; [m_native release]; @@ -248,6 +264,8 @@ NSMenuItem *QCocoaMenuItem::sync() m_native = nil; // create item below m_merged = false; } + } else { + m_textSynced = true; // NoRole, and that was set explicitly. So, nothing to do anymore. } if (!m_native) { @@ -257,23 +275,11 @@ NSMenuItem *QCocoaMenuItem::sync() [m_native setTag:reinterpret_cast<NSInteger>(this)]; } -// [m_native setHidden:YES]; -// [m_native setHidden:NO]; [m_native setHidden: !m_isVisible]; [m_native setEnabled: m_enabled]; - QString text = m_text; - QKeySequence accel = m_shortcut; - - { - int st = text.lastIndexOf(QLatin1Char('\t')); - if (st != -1) { - accel = QKeySequence(text.right(text.length()-(st+1))); - text.remove(st, text.length()-st); - } - } - text = mergeText(); - accel = mergeAccel(); + QString text = mergeText(); + QKeySequence accel = mergeAccel(); // Show multiple key sequences as part of the menu text. if (accel.count() > 1) @@ -323,7 +329,7 @@ QString QCocoaMenuItem::mergeText() return qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName()); } else if (m_native== [loader aboutQtMenuItem]) { if (m_text == QString("About Qt")) - return tr("About Qt"); + return msgAboutQt(); else return m_text; } else if (m_native == [loader preferencesMenuItem]) { diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm index 726fe5c6d2..62b722d2d2 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm @@ -41,15 +41,18 @@ #include "qcocoamenuloader.h" +#include "messages.h" #include "qcocoahelpers.h" #include "qcocoamenubar.h" #include "qcocoamenuitem.h" #include <QtCore/private/qcore_mac_p.h> +#include <QtCore/private/qthread_p.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qdir.h> #include <QtCore/qstring.h> #include <QtCore/qdebug.h> +#include <QtGui/private/qguiapplication_p.h> QT_FORWARD_DECLARE_CLASS(QCFString) QT_FORWARD_DECLARE_CLASS(QString) @@ -57,30 +60,6 @@ QT_FORWARD_DECLARE_CLASS(QString) QT_BEGIN_NAMESPACE -#ifndef QT_NO_TRANSLATION -static const char *application_menu_strings[] = { - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Services"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide %1"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Hide Others"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Show All"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Preferences..."), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","Quit %1"), - QT_TRANSLATE_NOOP("MAC_APPLICATION_MENU","About %1") - }; - -QString qt_mac_applicationmenu_string(int type) -{ - QString menuString = QString::fromLatin1(application_menu_strings[type]); - QString translated = qApp->translate("QMenuBar", application_menu_strings[type]); - if (translated != menuString) { - return translated; - } else { - return qApp->translate("MAC_APPLICATION_MENU", - application_menu_strings[type]); - } -} -#endif - /* Loads and instantiates the main app menu from the menu nib file(s). @@ -328,6 +307,7 @@ QT_END_NAMESPACE if ([item tag]) { QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]); + QScopedLoopLevelCounter loopLevelCounter(QGuiApplicationPrivate::instance()->threadData); cocoaItem->activated(); } } diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index ca84312059..2e5e65f577 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -65,6 +65,8 @@ public: NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; + Q_INVOKABLE void beep(); + static void *cglContextForContext(QOpenGLContext *context); static void *nsOpenGLContextForContext(QOpenGLContext* context); @@ -113,6 +115,9 @@ private: // Embedding NSViews as child QWindows static void setWindowContentView(QPlatformWindow *window, void *nsViewContentView); + // Set a QWindow as a "guest" (subwindow) of a non-QWindow + static void setEmbeddedInForeignView(QPlatformWindow *window, bool embedded); + // Register if a window should deliver touch events. Enabling // touch events has implications for delivery of other events, // for example by causing scrolling event lag. diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 84261ad273..873fa3eed9 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -120,10 +120,17 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setWindowContentView); if (resource.toLower() == "registertouchwindow") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerTouchWindow); + if (resource.toLower() == "setembeddedinforeignview") + return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setEmbeddedInForeignView); return 0; } +void QCocoaNativeInterface::beep() +{ + NSBeep(); +} + QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport() { #ifndef QT_NO_WIDGETS @@ -224,8 +231,17 @@ void QCocoaNativeInterface::setWindowContentView(QPlatformWindow *window, void * cocoaPlatformWindow->setContentView(reinterpret_cast<NSView *>(contentView)); } +void QCocoaNativeInterface::setEmbeddedInForeignView(QPlatformWindow *window, bool embedded) +{ + QCocoaWindow *cocoaPlatformWindow = static_cast<QCocoaWindow *>(window); + cocoaPlatformWindow->setEmbeddedInForeignView(embedded); +} + void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable) { + if (!window) + return; + // Make sure the QCocoaWindow is created when enabling. Disabling might // happen on window destruction, don't (re)create the QCocoaWindow then. if (enable) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index e1de5f0add..60f448044e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -106,6 +106,8 @@ public: void setWindowTitle(const QString &title); void setWindowFilePath(const QString &filePath); void setWindowIcon(const QIcon &icon); + void setAlertState(bool enabled); + bool isAlertState() const; void raise(); void lower(); bool isExposed() const; @@ -125,10 +127,12 @@ public: NSView *contentView() const; void setContentView(NSView *contentView); + void setEmbeddedInForeignView(bool subwindow); + void windowWillMove(); void windowDidMove(); void windowDidResize(); - void windowWillClose(); + bool windowShouldClose(); bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const; NSInteger windowLevel(Qt::WindowFlags flags); @@ -173,7 +177,10 @@ public: // for QNSView NSView *m_contentView; QNSView *m_qtView; NSWindow *m_nsWindow; - bool m_contentViewIsEmbedded; // true if the m_contentView is embedded in a "foregin" NSView hiearchy + + // TODO merge to one variable if possible + bool m_contentViewIsEmbedded; // true if the m_contentView is actually embedded in a "foreign" NSView hiearchy + bool m_contentViewIsToBeEmbedded; // true if the m_contentView is intended to be embedded in a "foreign" NSView hiearchy QNSWindowDelegate *m_nsWindowDelegate; Qt::WindowFlags m_windowFlags; @@ -190,6 +197,9 @@ public: // for QNSView bool m_frameStrutEventsEnabled; bool m_isExposed; int m_registerTouchCount; + + static const int NoAlertRequest; + NSInteger m_alertRequest; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index fc8eb0c503..5d1600dba6 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -191,10 +191,13 @@ static bool isMouseEvent(NSEvent *ev) @end +const int QCocoaWindow::NoAlertRequest = -1; + QCocoaWindow::QCocoaWindow(QWindow *tlw) : QPlatformWindow(tlw) , m_nsWindow(0) , m_contentViewIsEmbedded(false) + , m_contentViewIsToBeEmbedded(false) , m_nsWindowDelegate(0) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) @@ -205,6 +208,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_frameStrutEventsEnabled(false) , m_isExposed(false) , m_registerTouchCount(0) + , m_alertRequest(NoAlertRequest) { #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::QCocoaWindow" << this; @@ -406,7 +410,7 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; if (flags == Qt::Window) { styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask); - } else if (flags & Qt::Dialog) { + } else if ((flags & Qt::Dialog) == Qt::Dialog) { if (window()->modality() == Qt::NonModal) styleMask = NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask; else @@ -499,6 +503,21 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) } } +void QCocoaWindow::setAlertState(bool enabled) +{ + if (m_alertRequest == NoAlertRequest && enabled) { + m_alertRequest = [NSApp requestUserAttention:NSCriticalRequest]; + } else if (m_alertRequest != NoAlertRequest && !enabled) { + [NSApp cancelUserAttentionRequest:m_alertRequest]; + m_alertRequest = NoAlertRequest; + } +} + +bool QCocoaWindow::isAlertState() const +{ + return m_alertRequest != NoAlertRequest; +} + void QCocoaWindow::raise() { //qDebug() << "raise" << this; @@ -639,6 +658,12 @@ void QCocoaWindow::setContentView(NSView *contentView) recreateWindow(parent()); // Adds the content view to parent NSView } +void QCocoaWindow::setEmbeddedInForeignView(bool embedded) +{ + m_contentViewIsToBeEmbedded = embedded; + recreateWindow(0); // destroy what was already created +} + void QCocoaWindow::windowWillMove() { // Close any open popups on window move @@ -662,10 +687,12 @@ void QCocoaWindow::windowDidResize() [m_qtView updateGeometry]; } -void QCocoaWindow::windowWillClose() +bool QCocoaWindow::windowShouldClose() { - QWindowSystemInterface::handleCloseEvent(window()); + bool accepted = false; + QWindowSystemInterface::handleCloseEvent(window(), &accepted); QWindowSystemInterface::flushWindowSystemEvents(); + return accepted; } bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const @@ -700,8 +727,8 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) m_nsWindowDelegate = 0; } - if (window()->type() == Qt::SubWindow) { - // Subwindows don't have a NSWindow. + if (m_contentViewIsToBeEmbedded) { + // An embedded window doesn't have its own NSWindow. } else if (!parentWindow) { // Create a new NSWindow if this is a top-level window. m_nsWindow = createNSWindow(); @@ -866,7 +893,7 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) // if content view width or height is 0 then the window animations will crash so // do nothing except set the new state NSRect contentRect = [contentView() frame]; - if (contentRect.size.width < 0 || contentRect.size.height < 0) { + if (contentRect.size.width <= 0 || contentRect.size.height <= 0) { qWarning() << Q_FUNC_INFO << "invalid window content view size, check your window geometry"; m_synchedWindowState = newState; return; diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 68145ec914..67b16b4b32 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -107,7 +107,7 @@ QT_END_NAMESPACE - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent; - (int) convertKeyCode : (QChar)keyCode; -- (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags; ++ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags; - (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; - (void)keyDown:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 52e2d781ee..a53d6c4e44 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -172,7 +172,7 @@ static QTouchDevice *touchDevice = 0; - (void)viewDidMoveToSuperview { - if (!(m_window->type() & Qt::SubWindow)) + if (!(m_platformWindow->m_contentViewIsToBeEmbedded)) return; if ([self superview]) { @@ -208,7 +208,7 @@ static QTouchDevice *touchDevice = 0; NSRect rect = [self frame]; NSRect windowRect = [[self window] frame]; geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height); - } else if (m_window->type() & Qt::SubWindow) { + } else if (m_platformWindow->m_contentViewIsToBeEmbedded) { // embedded child window, use the frame rect ### merge with case below geometry = qt_mac_toQRect([self bounds]); } else { @@ -229,9 +229,9 @@ static QTouchDevice *touchDevice = 0; m_platformWindow->QPlatformWindow::setGeometry(geometry); // Don't send the geometry change if the QWindow is designated to be - // embedded in a foregin view hiearchy but has not actually been + // embedded in a foreign view hiearchy but has not actually been // embedded yet - it's too early. - if ((m_window->type() & Qt::SubWindow) && !m_platformWindow->m_contentViewIsEmbedded) + if (m_platformWindow->m_contentViewIsToBeEmbedded && !m_platformWindow->m_contentViewIsEmbedded) return; // Send a geometry change event to Qt, if it's ready to handle events @@ -494,7 +494,7 @@ static QTouchDevice *touchDevice = 0; QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); nativeDrag->setLastMouseEvent(theEvent, self); - Qt::KeyboardModifiers keyboardModifiers = [self convertKeyModifiers:[theEvent modifierFlags]]; + Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; QWindowSystemInterface::handleMouseEvent(m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers); } @@ -556,7 +556,7 @@ static QTouchDevice *touchDevice = 0; [inputManager handleMouseEvent:theEvent]; } } else { - if ([self convertKeyModifiers:[theEvent modifierFlags]] & Qt::MetaModifier) { + if ([QNSView convertKeyModifiers:[theEvent modifierFlags]] & Qt::MetaModifier) { m_buttons |= Qt::RightButton; m_sendUpAsRightButton = true; } else { @@ -826,7 +826,7 @@ static QTouchDevice *touchDevice = 0; if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) { NSEventPhase phase = [theEvent phase]; if (phase == NSEventPhaseBegan) { - currentWheelModifiers = [self convertKeyModifiers:[theEvent modifierFlags]]; + currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; } QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers); @@ -838,7 +838,7 @@ static QTouchDevice *touchDevice = 0; #endif { QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, - [self convertKeyModifiers:[theEvent modifierFlags]]); + [QNSView convertKeyModifiers:[theEvent modifierFlags]]); } } #endif //QT_NO_WHEELEVENT @@ -848,7 +848,7 @@ static QTouchDevice *touchDevice = 0; return qt_mac_cocoaKey2QtKey(keyChar); } -- (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags ++ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags { Qt::KeyboardModifiers qtMods =Qt::NoModifier; if (modifierFlags & NSShiftKeyMask) @@ -868,7 +868,7 @@ static QTouchDevice *touchDevice = 0; { ulong timestamp = [nsevent timestamp] * 1000; ulong nativeModifiers = [nsevent modifierFlags]; - Qt::KeyboardModifiers modifiers = [self convertKeyModifiers: nativeModifiers]; + Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers]; NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers]; NSString *characters = [nsevent characters]; @@ -948,7 +948,7 @@ static QTouchDevice *touchDevice = 0; { ulong timestamp = [nsevent timestamp] * 1000; ulong modifiers = [nsevent modifierFlags]; - Qt::KeyboardModifiers qmodifiers = [self convertKeyModifiers:modifiers]; + Qt::KeyboardModifiers qmodifiers = [QNSView convertKeyModifiers:modifiers]; // calculate the delta and remember the current modifiers for next time static ulong m_lastKnownModifiers; @@ -1278,7 +1278,7 @@ static QTouchDevice *touchDevice = 0; Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); // update these so selecting move/copy/link works - QGuiApplicationPrivate::modifier_buttons = [self convertKeyModifiers: [[NSApp currentEvent] modifierFlags]]; + QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]]; QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect()); if ([sender draggingSource] != nil) { diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index c43c0b5068..6ebb1f6ba8 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -106,9 +106,27 @@ // Hit a child, forward to child accessible interface. QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); + // FIXME: parent could be wrong QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self ]; [accessibleElement autorelease]; return [accessibleElement accessibilityHitTest:point]; } +- (id)accessibilityFocusedUIElement { + if (!m_window->accessibleRoot()) + return [super accessibilityFocusedUIElement]; + + QAccessibleInterface *childInterface = m_window->accessibleRoot()->focusChild(); + if (childInterface) { + QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); + // FIXME: parent could be wrong + QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self]; + [accessibleElement autorelease]; + return accessibleElement; + } + + // should not happen + return nil; +} + @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index 98ad7b8c9d..a5b46a971f 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -56,6 +56,7 @@ - (void)windowDidResize:(NSNotification *)notification; - (void)windowDidMove:(NSNotification *)notification; - (void)windowWillClose:(NSNotification *)notification; +- (BOOL)windowShouldClose:(NSNotification *)notification; @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index b19a401443..8e17936a78 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -80,12 +80,14 @@ } } -- (void)windowWillClose:(NSNotification *)notification +- (BOOL)windowShouldClose:(NSNotification *)notification { Q_UNUSED(notification); if (m_cocoaWindow) { - m_cocoaWindow->windowWillClose(); + return m_cocoaWindow->windowShouldClose(); } + + return YES; } @end diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index 329a0a3d9b..c352e0f2d2 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -52,7 +52,6 @@ class QIOSIntegration : public QPlatformIntegration, public QPlatformNativeInter { public: QIOSIntegration(); - ~QIOSIntegration(); bool hasCapability(Capability cap) const; diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index c7541c3e38..61fd1c3d60 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -79,11 +79,6 @@ QIOSIntegration::QIOSIntegration() QWindowSystemInterface::registerTouchDevice(m_touchDevice); } -QIOSIntegration::~QIOSIntegration() -{ - delete m_touchDevice; -} - bool QIOSIntegration::hasCapability(Capability cap) const { switch (cap) { diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 404b213966..9d3447a2e4 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -78,6 +78,10 @@ - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { Q_UNUSED(duration); + + if (!QCoreApplication::instance()) + return; // FIXME: Store orientation for later (?) + Qt::ScreenOrientation orientation = toQtScreenOrientation(UIDeviceOrientation(toInterfaceOrientation)); if (orientation == -1) return; diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index cefb6f9388..b86dbf7d46 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -77,6 +77,9 @@ public: int effectiveWidth() const; int effectiveHeight() const; + bool setMouseGrabEnabled(bool grab) { return grab; } + bool setKeyboardGrabEnabled(bool grab) { return grab; } + WId winId() const { return WId(m_view); }; QList<QWindowSystemInterface::TouchPoint> &touchPoints() { return m_touchPoints; } @@ -96,6 +99,9 @@ private: void raiseOrLower(bool raise); void updateWindowLevel(); bool blockedByModal(); + + inline Qt::WindowType windowType() { return static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask)); } + inline bool windowIsPopup() { return windowType() & Qt::Popup & ~Qt::Window; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 5edf81af93..b173fb786f 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -475,15 +475,17 @@ void QIOSWindow::raiseOrLower(bool raise) void QIOSWindow::updateWindowLevel() { - Qt::WindowType type = static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask)); + Qt::WindowType type = windowType(); if (type == Qt::ToolTip) m_windowLevel = 120; else if (window()->flags() & Qt::WindowStaysOnTopHint) m_windowLevel = 100; else if (window()->isModal()) + m_windowLevel = 40; + else if (type == Qt::Popup) m_windowLevel = 30; - else if (type & Qt::Popup & ~Qt::Window) + else if (type == Qt::SplashScreen) m_windowLevel = 20; else if (type == Qt::Tool) m_windowLevel = 10; diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index 7eb1bd30c0..ce61a8b092 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -721,22 +721,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildI if (varChildID.vt != VT_I4) return E_INVALIDARG; - - int childIndex = varChildID.lVal; - - QAccessibleInterface *acc = 0; - - - if (childIndex == 0) { - // Yes, some AT clients (Active Accessibility Object Inspector) - // actually ask for the same object. As a consequence, we need to clone ourselves: - acc = accessible; - } else if (childIndex < 0) { - acc = QAccessible::accessibleInterface((QAccessible::Id)childIndex); - } else { - acc = accessible->child(childIndex - 1); - } - + QAccessibleInterface *acc = childPointer(accessible, varChildID); if (acc) { *ppdispChild = QWindowsAccessibility::wrap(acc); return S_OK; @@ -825,7 +810,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT var QString descr; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; descr = child->text(QAccessible::Description); @@ -850,7 +835,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelp(VARIANT varID, BST QString help; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; help = child->text(QAccessible::Help); @@ -909,7 +894,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST QString name; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; name = child->text(QAccessible::Name); @@ -952,7 +937,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VAR QAccessible::Role role; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; role = child->role(); @@ -987,7 +972,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VA QAccessible::State state; if (varID.lVal) { - QAccessibleInterface *child = childPointer(varID); + QAccessibleInterface *child = childPointer(accessible, varID); if (!child) return E_FAIL; state = child->state(); diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h index ef17acf3e9..d4f141c5d8 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h @@ -153,13 +153,23 @@ protected: return 0; } - QAccessibleInterface *childPointer(VARIANT varID) + static QAccessibleInterface *childPointer(QAccessibleInterface *parent, VARIANT varID) { // -1 since windows API always uses 1 for the first child - QAccessibleInterface *iface = accessibleInterface(); - if (iface) - return accessibleInterface()->child(varID.lVal - 1); - return 0; + Q_ASSERT(parent); + + QAccessibleInterface *acc = 0; + int childIndex = varID.lVal; + if (childIndex == 0) { + // Yes, some AT clients (Active Accessibility Object Inspector) + // actually ask for the same object. As a consequence, we need to clone ourselves: + acc = parent; + } else if (childIndex < 0) { + acc = QAccessible::accessibleInterface((QAccessible::Id)childIndex); + } else { + acc = parent->child(childIndex - 1); + } + return acc; } private: diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index 3b2e9787a2..49ddf3106b 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -49,6 +49,10 @@ # define WM_THEMECHANGED 0x031A #endif +#ifndef GWL_HWNDPARENT +# define GWL_HWNDPARENT (-8) +#endif + /* Complement the definitions and declarations missing * when using MinGW or older Windows SDKs. */ diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 3f4555a31f..872fd07729 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -842,9 +842,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::FocusOutEvent: handleFocusEvent(et, platformWindow); return true; - case QtWindows::ShowEvent: - platformWindow->handleShown(); - return false; // Indicate transient children should be shown by windows (SW_PARENTOPENING) case QtWindows::HideEvent: platformWindow->handleHidden(); return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING) diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 5b84725edf..33b4eb4771 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -833,6 +833,7 @@ public: bool hideFiltersDetails() const { return m_hideFiltersDetails; } void setHideFiltersDetails(bool h) { m_hideFiltersDetails = h; } void setDefaultSuffix(const QString &s); + inline bool hasDefaultSuffix() const { return m_hasDefaultSuffix; } inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text); // Return the selected files for tracking in OnSelectionChanged(). @@ -857,6 +858,7 @@ public slots: protected: explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data); bool init(const CLSID &clsId, const IID &iid); + void setDefaultSuffixSys(const QString &s); inline IFileDialog * fileDialog() const { return m_fileDialog; } static QString itemPath(IShellItem *item); static QStringList libraryItemFolders(IShellItem *item); @@ -873,12 +875,13 @@ private: DWORD m_cookie; QStringList m_nameFilters; bool m_hideFiltersDetails; + bool m_hasDefaultSuffix; QWindowsFileDialogSharedData m_data; }; QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) : m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false), - m_data(data) + m_hasDefaultSuffix(false), m_data(data) { } @@ -1188,6 +1191,15 @@ void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters) void QWindowsNativeFileDialogBase::setDefaultSuffix(const QString &s) { + setDefaultSuffixSys(s); + m_hasDefaultSuffix = !s.isEmpty(); +} + +void QWindowsNativeFileDialogBase::setDefaultSuffixSys(const QString &s) +{ + // If this parameter is non-empty, it will be appended by the dialog for the 'Any files' + // filter ('*'). If this parameter is non-empty and the current filter has a suffix, + // the dialog will append the filter's suffix. wchar_t *wSuffix = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(s.utf16())); m_fileDialog->SetDefaultExtension(wSuffix); } @@ -1321,33 +1333,45 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnFileOk(IFileDialog *) class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase { + Q_OBJECT public: - explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) : - QWindowsNativeFileDialogBase(data) {} + explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data); virtual QStringList selectedFiles() const; virtual QStringList dialogResult() const; + +private slots: + void slotFilterSelected(const QString &); }; -// Append a suffix from the name filter "Foo files (*.foo;*.bar)" -// unless the file name already has one. -static inline QString appendSuffix(const QString &fileName, const QString &filter) +// Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo". +static inline QString suffixFromFilter(const QString &filter) { - const int lastDot = fileName.lastIndexOf(QLatin1Char('.')); - const int lastSlash = fileName.lastIndexOf(QLatin1Char('/')); - if (lastDot >= 0 && (lastSlash == -1 || lastDot > lastSlash)) - return fileName; int suffixPos = filter.indexOf(QLatin1String("(*.")); if (suffixPos < 0) - return fileName; + return QString(); suffixPos += 3; int endPos = filter.indexOf(QLatin1Char(' '), suffixPos + 1); if (endPos < 0) endPos = filter.indexOf(QLatin1Char(';'), suffixPos + 1); if (endPos < 0) endPos = filter.indexOf(QLatin1Char(')'), suffixPos + 1); - if (endPos < 0) - return fileName; - return fileName + QLatin1Char('.') + filter.mid(suffixPos, endPos - suffixPos); + return endPos >= 0 ? filter.mid(suffixPos, endPos - suffixPos) : QString(); +} + +QWindowsNativeSaveFileDialog::QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) + : QWindowsNativeFileDialogBase(data) +{ + connect(this, &QWindowsNativeFileDialogBase::filterSelected, + this, &QWindowsNativeSaveFileDialog::slotFilterSelected); +} + +void QWindowsNativeSaveFileDialog::slotFilterSelected(const QString &filter) +{ + // Cause the dialog to append the suffix of the current filter unless a default + // suffix is set (Note: Qt 4.8 sets the selected filter's suffix before + // calling GetSaveFileName()). + if (!hasDefaultSuffix()) + setDefaultSuffixSys(suffixFromFilter(filter)); } QStringList QWindowsNativeSaveFileDialog::dialogResult() const @@ -1355,7 +1379,7 @@ QStringList QWindowsNativeSaveFileDialog::dialogResult() const QStringList result; IShellItem *item = 0; if (SUCCEEDED(fileDialog()->GetResult(&item)) && item) - result.push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter())); + result.push_back(QWindowsNativeFileDialogBase::itemPath(item)); return result; } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 2a5e08cf41..010197d6d8 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -839,6 +839,15 @@ QWindowsWindow::~QWindowsWindow() destroyIcon(); } +void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) +{ + if (region.isEmpty() && !force) + clearFlag(Exposed); + else + setFlag(Exposed); + QWindowSystemInterface::handleExposeEvent(window(), region); +} + void QWindowsWindow::destroyWindow() { if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) @@ -942,13 +951,19 @@ void QWindowsWindow::setVisible(bool visible) if (m_data.hwnd) { if (visible) { show_sys(); - QWindowSystemInterface::handleExposeEvent(window(), - QRect(QPoint(), geometry().size())); + + // When the window is layered, we won't get WM_PAINT, and "we" are in control + // over the rendering of the window + // There is nobody waiting for this, so we don't need to flush afterwards. + QWindow *w = window(); + if (w->format().hasAlpha() || qFuzzyCompare(w->opacity(), qreal(1))) + fireExpose(QRect(0, 0, w->width(), w->height())); + } else { if (hasMouseCapture()) setMouseGrabEnabled(false); hide_sys(); - QWindowSystemInterface::handleExposeEvent(window(), QRegion()); + fireExpose(QRegion()); } } } @@ -998,6 +1013,24 @@ QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const return pos; } +// Update the transient parent for a toplevel window. The concept does not +// really exist on Windows, the relationship is set by passing a parent along with !WS_CHILD +// to window creation or by setting the parent using GWL_HWNDPARENT (as opposed to +// SetParent, which would make it a real child). +void QWindowsWindow::updateTransientParent() const +{ +#ifndef Q_OS_WINCE + // Update transient parent. + const HWND oldTransientParent = + GetAncestor(m_data.hwnd, GA_PARENT) == GetDesktopWindow() ? GetAncestor(m_data.hwnd, GA_ROOTOWNER) : HWND(0); + HWND newTransientParent = 0; + if (const QWindow *tp = window()->transientParent()) + newTransientParent = QWindowsWindow::handleOf(tp); + if (newTransientParent && newTransientParent != oldTransientParent) + SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, (LONG_PTR)newTransientParent); +#endif // !Q_OS_WINCE +} + // partially from QWidgetPrivate::show_sys() void QWindowsWindow::show_sys() const { @@ -1012,19 +1045,22 @@ void QWindowsWindow::show_sys() const sm = SW_SHOWMINIMIZED; if (!isVisible()) sm = SW_SHOWMINNOACTIVE; - } else if (state & Qt::WindowMaximized) { - sm = SW_SHOWMAXIMIZED; - // Windows will not behave correctly when we try to maximize a window which does not - // have minimize nor maximize buttons in the window frame. Windows would then ignore - // non-available geometry, and rather maximize the widget to the full screen, minus the - // window frame (caption). So, we do a trick here, by adding a maximize button before - // maximizing the widget, and then remove the maximize button afterwards. - if (flags & Qt::WindowTitleHint && - !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) { - fakedMaximize = TRUE; - setStyle(style() | WS_MAXIMIZEBOX); - } - } + } else { + updateTransientParent(); + if (state & Qt::WindowMaximized) { + sm = SW_SHOWMAXIMIZED; + // Windows will not behave correctly when we try to maximize a window which does not + // have minimize nor maximize buttons in the window frame. Windows would then ignore + // non-available geometry, and rather maximize the widget to the full screen, minus the + // window frame (caption). So, we do a trick here, by adding a maximize button before + // maximizing the widget, and then remove the maximize button afterwards. + if (flags & Qt::WindowTitleHint && + !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) { + fakedMaximize = TRUE; + setStyle(style() | WS_MAXIMIZEBOX); + } + } // Qt::WindowMaximized + } // !Qt::WindowMinimized } if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool) sm = SW_SHOWNOACTIVATE; @@ -1094,14 +1130,9 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const } } -void QWindowsWindow::handleShown() -{ - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); -} - void QWindowsWindow::handleHidden() { - QWindowSystemInterface::handleExposeEvent(window(), QRegion()); + fireExpose(QRegion()); } void QWindowsWindow::setGeometry(const QRect &rectIn) @@ -1267,28 +1298,21 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, if (message == WM_ERASEBKGND) // Backing store - ignored. return true; PAINTSTRUCT ps; - if (testFlag(OpenGLSurface)) { - // Observed painting problems with Aero style disabled (QTBUG-7865). - if (testFlag(OpenGLDoubleBuffered)) - InvalidateRect(hwnd, 0, false); - BeginPaint(hwnd, &ps); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(qrectFromRECT(ps.rcPaint))); - if (!QWindowsContext::instance()->asyncExpose()) - QWindowSystemInterface::flushWindowSystemEvents(); - EndPaint(hwnd, &ps); - } else { - BeginPaint(hwnd, &ps); - const QRect updateRect = qrectFromRECT(ps.rcPaint); + // Observed painting problems with Aero style disabled (QTBUG-7865). + if (testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered)) + InvalidateRect(hwnd, 0, false); - if (QWindowsContext::verboseIntegration) - qDebug() << __FUNCTION__ << this << window() << updateRect; + BeginPaint(hwnd, &ps); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(updateRect)); - if (!QWindowsContext::instance()->asyncExpose()) - QWindowSystemInterface::flushWindowSystemEvents(); - EndPaint(hwnd, &ps); - } + // If the a window is obscured by another window (such as a child window) + // we still need to send isExposed=true, for compatibility. + // Our tests depend on it. + fireExpose(QRegion(qrectFromRECT(ps.rcPaint)), true); + if (!QWindowsContext::instance()->asyncExpose()) + QWindowSystemInterface::flushWindowSystemEvents(); + + EndPaint(hwnd, &ps); return true; } @@ -1366,9 +1390,23 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) } } +// Return the effective screen for full screen mode in a virtual desktop. +static const QScreen *effectiveScreen(const QWindow *w) +{ + QPoint center = w->geometry().center(); + if (!w->isTopLevel()) + center = w->mapToGlobal(center); + const QScreen *screen = w->screen(); + if (!screen->geometry().contains(center)) + foreach (const QScreen *sibling, screen->virtualSiblings()) + if (sibling->geometry().contains(center)) + return sibling; + return screen; +} + bool QWindowsWindow::isFullScreen_sys() const { - return geometry_sys() == window()->screen()->geometry(); + return geometry_sys() == effectiveScreen(window())->geometry(); } /*! @@ -1444,7 +1482,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) newStyle |= WS_VISIBLE; setStyle(newStyle); - const QRect r = window()->screen()->geometry(); + const QRect r = effectiveScreen(window())->geometry(); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 2117ca50b8..6c735ede7d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -133,7 +133,8 @@ public: WithinSetStyle = 0x800, WithinDestroy = 0x1000, TouchRegistered = 0x2000, - AlertState = 0x4000 + AlertState = 0x4000, + Exposed = 0x08000 }; struct WindowData @@ -161,7 +162,7 @@ public: virtual void setVisible(bool visible); bool isVisible() const; - virtual bool isExposed() const { return m_windowState != Qt::WindowMinimized && isVisible(); } + virtual bool isExposed() const { return testFlag(Exposed); } virtual bool isActive() const; virtual bool isEmbedded(const QPlatformWindow *parentWindow) const; virtual QPoint mapToGlobal(const QPoint &pos) const; @@ -217,7 +218,6 @@ public: void handleMoved(); void handleResized(int wParam); - void handleShown(); void handleHidden(); static inline HWND handleOf(const QWindow *w); @@ -272,12 +272,14 @@ private: inline bool isFullScreen_sys() const; inline void setWindowState_sys(Qt::WindowState newState); inline void setParent_sys(const QPlatformWindow *parent) const; + inline void updateTransientParent() const; void destroyWindow(); void registerDropSite(); void unregisterDropSite(); void handleGeometryChange(); void handleWindowStateChange(Qt::WindowState state); inline void destroyIcon(); + void fireExpose(const QRegion ®ion, bool force=false); mutable WindowData m_data; mutable unsigned m_flags; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 1504bd99d2..10a8f26614 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -242,8 +242,9 @@ void QXcbConnection::updateScreens() ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded(screen); } -QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char *displayName) +QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName) : m_connection(0) + , m_canGrabServer(canGrabServer) , m_primaryScreen(0) , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) , m_nativeInterface(nativeInterface) @@ -344,6 +345,10 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char m_drag = new QXcbDrag(this); #endif + m_startupId = qgetenv("DESKTOP_STARTUP_ID"); + if (!m_startupId.isNull()) + qunsetenv("DESKTOP_STARTUP_ID"); + sync(); } @@ -386,28 +391,36 @@ QXcbConnection::~QXcbConnection() delete m_keyboard; } -void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window) +void QXcbConnection::addWindowEventListener(xcb_window_t id, QXcbWindowEventListener *eventListener) { - m_mapper.insert(id, window); + m_mapper.insert(id, eventListener); } -void QXcbConnection::removeWindow(xcb_window_t id) +void QXcbConnection::removeWindowEventListener(xcb_window_t id) { m_mapper.remove(id); } -QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) +QXcbWindowEventListener *QXcbConnection::windowEventListenerFromId(xcb_window_t id) { return m_mapper.value(id, 0); } +QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) +{ + QXcbWindowEventListener *listener = m_mapper.value(id, 0); + if (listener) + return listener->toWindow(); + return 0; +} + #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \ { \ event_t *e = (event_t *)event; \ - if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) { \ - handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \ + if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \ + handled = eventListener->handleGenericEvent(event, &result); \ if (!handled) \ - platformWindow->handler(e); \ + eventListener->handler(e); \ } \ } \ break; @@ -415,10 +428,10 @@ break; #define HANDLE_KEYBOARD_EVENT(event_t, handler) \ { \ event_t *e = (event_t *)event; \ - if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) { \ - handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \ + if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \ + handled = eventListener->handleGenericEvent(event, &result); \ if (!handled) \ - m_keyboard->handler(m_focusWindow, e); \ + m_keyboard->handler(m_focusWindow ? m_focusWindow : eventListener, e); \ } \ } \ break; @@ -948,6 +961,18 @@ void QXcbConnection::setFocusWindow(QXcbWindow *w) m_focusWindow = w; } +void QXcbConnection::grabServer() +{ + if (m_canGrabServer) + xcb_grab_server(m_connection); +} + +void QXcbConnection::ungrabServer() +{ + if (m_canGrabServer) + xcb_ungrab_server(m_connection); +} + void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) { xcb_client_message_event_t event; diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index f69a8a9f35..44c0e28dd5 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -80,8 +80,6 @@ class QXcbClipboard; class QXcbWMSupport; class QXcbNativeInterface; -typedef QHash<xcb_window_t, QXcbWindow *> WindowMapper; - namespace QXcbAtom { enum Atom { // window-manager <-> client protocols @@ -301,12 +299,36 @@ private: XcbPollForQueuedEventFunctionPointer m_xcb_poll_for_queued_event; }; +class QXcbWindowEventListener +{ +public: + virtual bool handleGenericEvent(xcb_generic_event_t *, long *) { return false; } + + virtual void handleExposeEvent(const xcb_expose_event_t *) {} + virtual void handleClientMessageEvent(const xcb_client_message_event_t *) {} + virtual void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *) {} + virtual void handleMapNotifyEvent(const xcb_map_notify_event_t *) {} + virtual void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *) {} + virtual void handleButtonPressEvent(const xcb_button_press_event_t *) {} + virtual void handleButtonReleaseEvent(const xcb_button_release_event_t *) {} + virtual void handleMotionNotifyEvent(const xcb_motion_notify_event_t *) {} + virtual void handleEnterNotifyEvent(const xcb_enter_notify_event_t *) {} + virtual void handleLeaveNotifyEvent(const xcb_leave_notify_event_t *) {} + virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {} + virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {} + virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {} + + virtual QXcbWindow *toWindow() { return 0; } +}; + +typedef QHash<xcb_window_t, QXcbWindowEventListener *> WindowMapper; + class QAbstractEventDispatcher; class QXcbConnection : public QObject { Q_OBJECT public: - QXcbConnection(QXcbNativeInterface *nativeInterface, const char *displayName = 0); + QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName = 0); ~QXcbConnection(); QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); } @@ -356,8 +378,9 @@ public: void handleXcbError(xcb_generic_error_t *error); void handleXcbEvent(xcb_generic_event_t *event); - void addWindow(xcb_window_t id, QXcbWindow *window); - void removeWindow(xcb_window_t id); + void addWindowEventListener(xcb_window_t id, QXcbWindowEventListener *eventListener); + void removeWindowEventListener(xcb_window_t id); + QXcbWindowEventListener *windowEventListenerFromId(xcb_window_t id); QXcbWindow *platformWindowFromId(xcb_window_t id); xcb_generic_event_t *checkEvent(int type); @@ -388,6 +411,13 @@ public: QXcbWindow *focusWindow() const { return m_focusWindow; } void setFocusWindow(QXcbWindow *); + QByteArray startupId() const { return m_startupId; } + void clearStartupId() { m_startupId.clear(); } + + void grabServer(); + void ungrabServer(); + + QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; } private slots: void processXcbEvents(); @@ -451,6 +481,7 @@ private: xcb_connection_t *m_connection; const xcb_setup_t *m_setup; + bool m_canGrabServer; QList<QXcbScreen *> m_screens; int m_primaryScreen; @@ -516,6 +547,8 @@ private: Qt::MouseButtons m_buttons; QXcbWindow *m_focusWindow; + + QByteArray m_startupId; }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 5dbac93fde..dceac09be5 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -1160,7 +1160,7 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) if (desktop_proxy) // *WE* already have one. return false; - xcb_grab_server(xcb_connection()); + connection()->grabServer(); // As per Xdnd4, use XdndProxy xcb_window_t proxy_id = xdndProxy(connection(), w->xcb_window()); @@ -1176,7 +1176,7 @@ bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) XCB_ATOM_WINDOW, 32, 1, &proxy_id); } - xcb_ungrab_server(xcb_connection()); + connection()->ungrabServer(); } else { xdnd_widget = w; } diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index f0cabea43d..dd1466d23c 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -91,8 +91,34 @@ #endif #endif +#include <QtCore/QFileInfo> + QT_BEGIN_NAMESPACE +#if defined(QT_DEBUG) && defined(Q_OS_LINUX) +// Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,. +// or, for older Linuxes, read out 'cmdline'. +static bool runningUnderDebugger() +{ + const QString parentProc = QLatin1String("/proc/") + QString::number(getppid()); + const QFileInfo parentProcExe(parentProc + QLatin1String("/exe")); + if (parentProcExe.isSymLink()) + return parentProcExe.symLinkTarget().endsWith(QLatin1String("/gdb")); + QFile f(parentProc + QLatin1String("/cmdline")); + if (!f.open(QIODevice::ReadOnly)) + return false; + QByteArray s; + char c; + while (f.getChar(&c) && c) { + if (c == '/') + s.clear(); + else + s += c; + } + return s == "gdb"; +} +#endif + QXcbIntegration::QXcbIntegration(const QStringList ¶meters) : m_eventDispatcher(createUnixEventDispatcher()) , m_services(new QGenericUnixServices) @@ -104,7 +130,15 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters) #endif m_nativeInterface.reset(new QXcbNativeInterface); - m_connections << new QXcbConnection(m_nativeInterface.data()); + bool canGrab = true; + #if defined(QT_DEBUG) && defined(Q_OS_LINUX) + canGrab = !runningUnderDebugger(); + #endif + static bool canNotGrabEnv = qgetenv("QT_XCB_NO_GRAB_SERVER").length(); + if (canNotGrabEnv) + canGrab = false; + + m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab); for (int i = 0; i < parameters.size() - 1; i += 2) { #ifdef Q_XCB_DEBUG diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 6db9d82cca..451dc43475 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -95,6 +95,8 @@ public: QStringList themeNames() const; QPlatformTheme *createPlatformTheme(const QString &name) const; + QXcbConnection *defaultConnection() const { return m_connections.first(); } + private: QList<QXcbConnection *> m_connections; diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 02f10bba89..c66ed53152 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -1172,14 +1172,20 @@ xcb_keysym_t QXcbKeyboard::lookupString(QWindow *window, uint state, xcb_keycode #endif } -void QXcbKeyboard::handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event) +void QXcbKeyboard::handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event) { + QXcbWindow *window = eventListener->toWindow(); + if (!window) + return; window->updateNetWmUserTime(event->time); handleKeyEvent(window->window(), QEvent::KeyPress, event->detail, event->state, event->time); } -void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event) +void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindowEventListener *eventListener, const xcb_key_release_event_t *event) { + QXcbWindow *window = eventListener->toWindow(); + if (!window) + return; handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time); } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index da25c51107..3c71daa57f 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -58,8 +58,8 @@ public: QXcbKeyboard(QXcbConnection *connection); ~QXcbKeyboard(); - void handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event); - void handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event); + void handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event); + void handleKeyReleaseEvent(QXcbWindowEventListener *eventListener, const xcb_key_release_event_t *event); void handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 6241898462..da60cfd2bd 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -42,6 +42,7 @@ #include "qxcbnativeinterface.h" #include "qxcbscreen.h" +#include "qxcbintegration.h" #include <private/qguiapplication_p.h> #include <QtCore/QMap> @@ -77,6 +78,8 @@ public: insert("glxcontext",QXcbNativeInterface::GLXContext); insert("apptime",QXcbNativeInterface::AppTime); insert("appusertime",QXcbNativeInterface::AppUserTime); + insert("hintstyle", QXcbNativeInterface::ScreenHintStyle); + insert("startupid", QXcbNativeInterface::StartupId); } }; @@ -98,6 +101,25 @@ void QXcbNativeInterface::beep() // For QApplication::beep() #endif } +void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) +{ + QByteArray lowerCaseResource = resourceString.toLower(); + if (!qXcbResourceMap()->contains(lowerCaseResource)) + return 0; + + ResourceType resource = qXcbResourceMap()->value(lowerCaseResource); + void *result = 0; + switch (resource) { + case StartupId: + result = startupId(); + break; + default: + break; + } + + return result; +} + void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) { QByteArray lowerCaseResource = resourceString.toLower(); @@ -139,6 +161,8 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resource, Q case AppUserTime: result = appUserTime(xcbScreen); break; + case ScreenHintStyle: + result = reinterpret_cast<void *>(xcbScreen->hintStyle() + 1); default: break; } @@ -193,6 +217,15 @@ void *QXcbNativeInterface::appUserTime(const QXcbScreen *screen) return reinterpret_cast<void *>(quintptr(screen->connection()->netWmUserTime())); } +void *QXcbNativeInterface::startupId() +{ + QXcbIntegration* integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); + QXcbConnection *defaultConnection = integration->defaultConnection(); + if (defaultConnection) + return reinterpret_cast<void *>(const_cast<char *>(defaultConnection->startupId().constData())); + return 0; +} + void QXcbNativeInterface::setAppTime(QScreen* screen, xcb_timestamp_t time) { static_cast<QXcbScreen *>(screen->handle())->connection()->setTime(time); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index db0fa3e2ca..e27bfa5a46 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -64,11 +64,14 @@ public: EglContext, GLXContext, AppTime, - AppUserTime + AppUserTime, + ScreenHintStyle, + StartupId }; QXcbNativeInterface(); + void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen); void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); @@ -85,6 +88,7 @@ public: void *graphicsDeviceForWindow(QWindow *window); void *appTime(const QXcbScreen *screen); void *appUserTime(const QXcbScreen *screen); + void *startupId(); static void setAppTime(QScreen *screen, xcb_timestamp_t time); static void setAppUserTime(QScreen *screen, xcb_timestamp_t time); static void *eglContextForContext(QOpenGLContext *context); diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 7ae4e19dc3..a6ead49a27 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -67,6 +67,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, , m_number(number) , m_refreshRate(60) , m_forcedDpi(-1) + , m_hintStyle(QFontEngine::HintStyle(-1)) { if (connection->hasXRandr()) xcb_randr_select_input(xcb_connection(), screen()->root, true); @@ -232,6 +233,40 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const return 0; } +void QXcbScreen::windowShown(QXcbWindow *window) +{ + // Freedesktop.org Startup Notification + if (!connection()->startupId().isEmpty() && window->window()->isTopLevel()) { + sendStartupMessage(QByteArrayLiteral("remove: ID=") + connection()->startupId()); + connection()->clearStartupId(); + } +} + +void QXcbScreen::sendStartupMessage(const QByteArray &message) const +{ + xcb_window_t rootWindow = root(); + + xcb_client_message_event_t ev; + ev.response_type = XCB_CLIENT_MESSAGE; + ev.format = 8; + ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO_BEGIN); + ev.window = rootWindow; + int sent = 0; + int length = message.length() + 1; // include NUL byte + const char *data = message.constData(); + do { + if (sent == 20) + ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO); + + const int start = sent; + const int numBytes = qMin(length - start, 20); + memcpy(ev.data.data8, data + start, numBytes); + xcb_send_event(connection()->xcb_connection(), false, rootWindow, XCB_EVENT_MASK_PROPERTY_CHANGE, (const char *) &ev); + + sent += numBytes; + } while (sent < length); +} + const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const { QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid); @@ -481,6 +516,35 @@ QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) return result; } +bool QXcbScreen::xResource(const QByteArray &identifier, + const QByteArray &expectedIdentifier, + int *value) +{ + Q_ASSERT(value != 0); + if (identifier.startsWith(expectedIdentifier)) { + QByteArray stringValue = identifier.mid(expectedIdentifier.size()); + + bool ok; + *value = stringValue.toInt(&ok); + if (!ok) { + if (stringValue == "hintfull") + *value = QFontEngine::HintFull; + else if (stringValue == "hintnone") + *value = QFontEngine::HintNone; + else if (stringValue == "hintmedium") + *value = QFontEngine::HintMedium; + else if (stringValue == "hintslight") + *value = QFontEngine::HintLight; + + return *value != 0; + } + + return true; + } + + return false; +} + void QXcbScreen::readXResources() { int offset = 0; @@ -508,13 +572,11 @@ void QXcbScreen::readXResources() QList<QByteArray> split = resources.split('\n'); for (int i = 0; i < split.size(); ++i) { const QByteArray &r = split.at(i); - if (r.startsWith("Xft.dpi:\t")) { - bool ok; - int dpi = r.mid(sizeof("Xft.dpi:")).toInt(&ok); - if (ok) - m_forcedDpi = dpi; - break; - } + int value; + if (xResource(r, "Xft.dpi:\t", &value)) + m_forcedDpi = value; + else if (xResource(r, "Xft.hintstyle:\t", &value)) + m_hintStyle = QFontEngine::HintStyle(value); } } diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 4c7d7f2c1c..0382be8a29 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -50,6 +50,8 @@ #include "qxcbobject.h" +#include <private/qfontengine_p.h> + QT_BEGIN_NAMESPACE class QXcbConnection; @@ -85,6 +87,7 @@ public: xcb_window_t clientLeader() const { return m_clientLeader; } + void windowShown(QXcbWindow *window); QString windowManagerName() const { return m_windowManagerName; } bool syncRequestSupported() const { return m_syncRequestSupported; } @@ -97,7 +100,14 @@ public: void updateRefreshRate(); void readXResources(); + + QFontEngine::HintStyle hintStyle() const { return m_hintStyle; } private: + static bool xResource(const QByteArray &identifier, + const QByteArray &expectedIdentifier, + int *value); + void sendStartupMessage(const QByteArray &message) const; + xcb_screen_t *m_screen; xcb_randr_crtc_t m_crtc; QString m_outputName; @@ -116,6 +126,7 @@ private: QXcbCursor *m_cursor; int m_refreshRate; int m_forcedDpi; + QFontEngine::HintStyle m_hintStyle; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 68ccbfb8c0..c845b875bf 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -46,12 +46,14 @@ #include <QtGui/QIcon> #include <QtGui/QRegion> +#include "qxcbintegration.h" #include "qxcbconnection.h" #include "qxcbscreen.h" #include "qxcbdrag.h" #include "qxcbkeyboard.h" #include "qxcbwmsupport.h" #include "qxcbimage.h" +#include "qxcbnativeinterface.h" #include <qpa/qplatformintegration.h> @@ -170,7 +172,9 @@ static inline QImage::Format imageFormatForDepth(int depth) case 32: return QImage::Format_ARGB32_Premultiplied; case 24: return QImage::Format_RGB32; case 16: return QImage::Format_RGB16; - default: return QImage::Format_Invalid; + default: + qWarning("Unsupported screen depth: %d", depth); + return QImage::Format_Invalid; } } @@ -221,7 +225,7 @@ void QXcbWindow::create() m_window = m_screen->root(); m_depth = m_screen->screen()->root_depth; m_imageFormat = imageFormatForDepth(m_depth); - connection()->addWindow(m_window, this); + connection()->addWindowEventListener(m_window, this); return; } @@ -344,7 +348,7 @@ void QXcbWindow::create() 0)); // value list } - connection()->addWindow(m_window, this); + connection()->addWindowEventListener(m_window, this); Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); @@ -478,7 +482,7 @@ void QXcbWindow::destroy() xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow); m_netWmUserTimeWindow = XCB_NONE; } - connection()->removeWindow(m_window); + connection()->removeWindowEventListener(m_window); Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); m_window = 0; } @@ -651,6 +655,9 @@ void QXcbWindow::show() updateNetWmUserTime(connection()->time()); Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); + + m_screen->windowShown(this); + xcb_flush(xcb_connection()); connection()->sync(); @@ -1441,6 +1448,14 @@ private: bool m_pending; }; +bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result) +{ + return QWindowSystemInterface::handleNativeEvent(window(), + connection()->nativeInterface()->genericEventFilterType(), + event, + result); +} + void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { QRect rect(event->x, event->y, event->width, event->height); @@ -1486,6 +1501,11 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even connection()->setTime(event->data.data32[1]); m_syncValue.lo = event->data.data32[2]; m_syncValue.hi = event->data.data32[3]; +#ifndef QT_NO_WHATSTHIS + } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_CONTEXT_HELP)) { + QEvent *e = new QEvent(QEvent::EnterWhatsThisMode); + QGuiApplication::postEvent(QGuiApplication::instance(), e); +#endif } else { qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); } @@ -1671,6 +1691,8 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) handleMouseEvent(event->time, local, global, modifiers); } +QXcbWindow *QXcbWindow::toWindow() { return this; } + void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers) { connection()->setTime(time); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 300596845e..5601a115e9 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE class QXcbScreen; class QXcbEGLSurface; class QIcon; -class QXcbWindow : public QXcbObject, public QPlatformWindow +class QXcbWindow : public QXcbObject, public QXcbWindowEventListener, public QPlatformWindow { public: enum NetWmState { @@ -126,20 +126,24 @@ public: uint depth() const { return m_depth; } QImage::Format imageFormat() const { return m_imageFormat; } - void handleExposeEvent(const xcb_expose_event_t *event); - void handleClientMessageEvent(const xcb_client_message_event_t *event); - void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event); - void handleMapNotifyEvent(const xcb_map_notify_event_t *event); - void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event); - void handleButtonPressEvent(const xcb_button_press_event_t *event); - void handleButtonReleaseEvent(const xcb_button_release_event_t *event); - void handleMotionNotifyEvent(const xcb_motion_notify_event_t *event); - - void handleEnterNotifyEvent(const xcb_enter_notify_event_t *event); - void handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event); - void handleFocusInEvent(const xcb_focus_in_event_t *event); - void handleFocusOutEvent(const xcb_focus_out_event_t *event); - void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event); + bool handleGenericEvent(xcb_generic_event_t *event, long *result) Q_DECL_OVERRIDE; + + void handleExposeEvent(const xcb_expose_event_t *event) Q_DECL_OVERRIDE; + void handleClientMessageEvent(const xcb_client_message_event_t *event) Q_DECL_OVERRIDE; + void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event) Q_DECL_OVERRIDE; + void handleMapNotifyEvent(const xcb_map_notify_event_t *event) Q_DECL_OVERRIDE; + void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) Q_DECL_OVERRIDE; + void handleButtonPressEvent(const xcb_button_press_event_t *event) Q_DECL_OVERRIDE; + void handleButtonReleaseEvent(const xcb_button_release_event_t *event) Q_DECL_OVERRIDE; + void handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) Q_DECL_OVERRIDE; + + void handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) Q_DECL_OVERRIDE; + void handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) Q_DECL_OVERRIDE; + void handleFocusInEvent(const xcb_focus_in_event_t *event) Q_DECL_OVERRIDE; + void handleFocusOutEvent(const xcb_focus_out_event_t *event) Q_DECL_OVERRIDE; + void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) Q_DECL_OVERRIDE; + + QXcbWindow *toWindow() Q_DECL_OVERRIDE; void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers); diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index d36a224d8e..77accc6e9d 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -958,9 +958,8 @@ bool QODBCResult::reset (const QString& query) return false; } - SQLINTEGER bufferLength; - SQLULEN isScrollable; - r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, &bufferLength); + SQLULEN isScrollable = 0; + r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0); if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) QSqlResult::setForwardOnly(isScrollable==SQL_NONSCROLLABLE); @@ -1106,7 +1105,7 @@ bool QODBCResult::fetchLast() "Unable to fetch last"), QSqlError::ConnectionError, d)); return false; } - SQLINTEGER currRow; + SQLULEN currRow = 0; r = SQLGetStmtAttr(d->hStmt, SQL_ROW_NUMBER, &currRow, @@ -1592,9 +1591,8 @@ bool QODBCResult::exec() return false; } - SQLINTEGER bufferLength; - SQLULEN isScrollable; - r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, &bufferLength); + SQLULEN isScrollable = 0; + r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0); if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) QSqlResult::setForwardOnly(isScrollable==SQL_NONSCROLLABLE); diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index c5dc7d17c9..d5e079d910 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -4184,7 +4184,7 @@ void HtmlGenerator::generateManifestFile(QString manifest, QString element) writer.writeEndElement(); // description // Add words from module name as tags (QtQuickControls -> qt,quick,controls) - QRegExp re("([A-Z][a-z0-9]+)"); + QRegExp re("([A-Z]+[a-z0-9]*)"); int pos = 0; while ((pos = re.indexIn(project, pos)) != -1) { tags << re.cap(1).toLower(); diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index 833320da16..4ec828ac83 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -133,10 +133,14 @@ public: bool copy() { +#ifdef QT_NO_CLIPBOARD + return false; +#else if (!copyAvailable) return false; textEdit->copy(); return true; +#endif } private slots: diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp index f2c3c4702f..7d8512adc4 100644 --- a/src/widgets/itemviews/qitemdelegate.cpp +++ b/src/widgets/itemviews/qitemdelegate.cpp @@ -523,7 +523,10 @@ QWidget *QItemDelegate::createEditor(QWidget *parent, const QItemEditorFactory *factory = d->f; if (factory == 0) factory = QItemEditorFactory::defaultFactory(); - return factory->createEditor(index.data(Qt::EditRole).userType(), parent); + QWidget *w = factory->createEditor(index.data(Qt::EditRole).userType(), parent); + if (w) + w->setFocusPolicy(Qt::WheelFocus); + return w; } /*! diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index 37c52948b0..471f8b149c 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -1126,10 +1126,15 @@ void QTableView::doItemsLayout() { Q_D(QTableView); QAbstractItemView::doItemsLayout(); - if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) - d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value()); - else + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { + const int max = verticalScrollBar()->maximum(); + if (max > 0 && verticalScrollBar()->value() == max) + d->verticalHeader->setOffsetToLastSection(); + else + d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value()); + } else { d->verticalHeader->setOffset(verticalScrollBar()->value()); + } if (!d->verticalHeader->updatesEnabled()) d->verticalHeader->setUpdatesEnabled(true); } diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index 962ed97762..dd450daaea 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -879,7 +879,7 @@ bool QTreeView::isSortingEnabled() const \property QTreeView::animated \brief whether animations are enabled - If this property is true the treeview will animate expandsion + If this property is true the treeview will animate expansion and collapsing of branches. If this property is false, the treeview will expand or collapse branches immediately without showing the animation. diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index d036f6bada..b8d3117a41 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -72,6 +72,9 @@ #include <QtGui/qstylehints.h> #include <QtGui/qinputmethod.h> #include <qpa/qplatformtheme.h> +#ifndef QT_NO_WHATSTHIS +#include <QtWidgets/QWhatsThis> +#endif #include "private/qkeymapper_p.h" @@ -1856,6 +1859,11 @@ bool QApplication::event(QEvent *e) } else if (te->timerId() == d->toolTipFallAsleep.timerId()) { d->toolTipFallAsleep.stop(); } +#ifndef QT_NO_WHATSTHIS + } else if (e->type() == QEvent::EnterWhatsThisMode) { + QWhatsThis::enterWhatsThisMode(); + return true; +#endif } if(e->type() == QEvent::LanguageChange) { diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp index 6567ef5c2f..2761c84a8d 100644 --- a/src/widgets/kernel/qapplication_qpa.cpp +++ b/src/widgets/kernel/qapplication_qpa.cpp @@ -415,7 +415,7 @@ void QApplication::beep() void QApplication::alert(QWidget *widget, int duration) { if (widget) { - if (widget->window()->isActiveWindow()&& !widget->window()->windowState() & Qt::WindowMinimized) + if (widget->window()->isActiveWindow() && !(widget->window()->windowState() & Qt::WindowMinimized)) return; if (QWindow *window= QApplicationPrivate::windowForWidget(widget)) window->alert(duration); diff --git a/src/widgets/kernel/qboxlayout.cpp b/src/widgets/kernel/qboxlayout.cpp index e1a7903628..d0e7a16999 100644 --- a/src/widgets/kernel/qboxlayout.cpp +++ b/src/widgets/kernel/qboxlayout.cpp @@ -942,7 +942,8 @@ void QBoxLayout::insertSpacerItem(int index, QSpacerItem *spacerItem) void QBoxLayout::insertLayout(int index, QLayout *layout, int stretch) { Q_D(QBoxLayout); - addChildLayout(layout); + if (!adoptLayout(layout)) + return; if (index < 0) // append index = d->list.count(); QBoxLayoutItem *it = new QBoxLayoutItem(layout, stretch); diff --git a/src/widgets/kernel/qformlayout.cpp b/src/widgets/kernel/qformlayout.cpp index e2d25de537..669faac4f6 100644 --- a/src/widgets/kernel/qformlayout.cpp +++ b/src/widgets/kernel/qformlayout.cpp @@ -976,8 +976,8 @@ void QFormLayoutPrivate::setLayout(int row, QFormLayout::ItemRole role, QLayout { if (layout) { Q_Q(QFormLayout); - q->addChildLayout(layout); - setItem(row, role, layout); + if (q->adoptLayout(layout)) + setItem(row, role, layout); } } diff --git a/src/widgets/kernel/qgridlayout.cpp b/src/widgets/kernel/qgridlayout.cpp index 12049f3303..96820e3891 100644 --- a/src/widgets/kernel/qgridlayout.cpp +++ b/src/widgets/kernel/qgridlayout.cpp @@ -1505,7 +1505,8 @@ void QGridLayout::addWidget(QWidget *widget, int fromRow, int fromColumn, void QGridLayout::addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment) { Q_D(QGridLayout); - addChildLayout(layout); + if (!adoptLayout(layout)) + return; QGridBox *b = new QGridBox(layout); b->setAlignment(alignment); d->add(b, row, column); @@ -1524,7 +1525,8 @@ void QGridLayout::addLayout(QLayout *layout, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment) { Q_D(QGridLayout); - addChildLayout(layout); + if (!adoptLayout(layout)) + return; QGridBox *b = new QGridBox(layout); b->setAlignment(alignment); d->add(b, row, (rowSpan < 0) ? -1 : row + rowSpan - 1, column, (columnSpan < 0) ? -1 : column + columnSpan - 1); diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index d59a9db75d..0402f9939a 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -806,6 +806,16 @@ void QLayout::addChildLayout(QLayout *l) } +/*! + \internal + */ +bool QLayout::adoptLayout(QLayout *layout) +{ + const bool ok = !layout->parent(); + addChildLayout(layout); + return ok; +} + #ifdef QT_DEBUG static bool layoutDebug() { diff --git a/src/widgets/kernel/qlayout.h b/src/widgets/kernel/qlayout.h index c293939bd3..6f43c2b28a 100644 --- a/src/widgets/kernel/qlayout.h +++ b/src/widgets/kernel/qlayout.h @@ -148,6 +148,7 @@ protected: void childEvent(QChildEvent *e); void addChildLayout(QLayout *l); void addChildWidget(QWidget *w); + bool adoptLayout(QLayout *layout); QRect alignmentRect(const QRect&) const; protected: diff --git a/src/widgets/kernel/qstandardgestures.cpp b/src/widgets/kernel/qstandardgestures.cpp index e3131e7e56..f4307e9737 100644 --- a/src/widgets/kernel/qstandardgestures.cpp +++ b/src/widgets/kernel/qstandardgestures.cpp @@ -59,8 +59,8 @@ QPanGestureRecognizer::QPanGestureRecognizer() QGesture *QPanGestureRecognizer::create(QObject *target) { if (target && target->isWidgetType()) { -#if defined(Q_OS_WIN) && !defined(QT_NO_NATIVE_GESTURES) - // for scroll areas on Windows we want to use native gestures instead +#if ((defined(Q_OS_MAC) && !defined(Q_OS_IOS)) || defined(Q_OS_WIN)) && !defined(QT_NO_NATIVE_GESTURES) + // for scroll areas on Windows and Mac OS X we want to use native gestures instead if (!qobject_cast<QAbstractScrollArea *>(target->parent())) static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); #else diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 90cfb3446f..cb7761add7 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -8434,8 +8434,6 @@ void QWidget::mouseReleaseEvent(QMouseEvent *event) This event handler, for event \a event, can be reimplemented in a subclass to receive mouse double click events for the widget. - The default implementation generates a normal mouse press event. - \note The widget will also receive mouse press and mouse release events in addition to the double click event. It is up to the developer to ensure that the application interprets these events @@ -9876,11 +9874,16 @@ void QWidget::update() */ void QWidget::update(const QRect &rect) { - if (!isVisible() || !updatesEnabled() || rect.isEmpty()) + if (!isVisible() || !updatesEnabled()) + return; + + QRect r = rect & QWidget::rect(); + + if (r.isEmpty()) return; if (testAttribute(Qt::WA_WState_InPaintEvent)) { - QApplication::postEvent(this, new QUpdateLaterEvent(rect)); + QApplication::postEvent(this, new QUpdateLaterEvent(r)); return; } @@ -9893,9 +9896,9 @@ void QWidget::update(const QRect &rect) #endif // Q_WS_MAC QTLWExtra *tlwExtra = window()->d_func()->maybeTopData(); if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) - tlwExtra->backingStoreTracker->markDirty(rect, this); + tlwExtra->backingStoreTracker->markDirty(r, this); } else { - d_func()->repaint_sys(rect); + d_func()->repaint_sys(r); } } diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index fdc72ee23c..a4da98815b 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -172,7 +172,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry())); d->deactivateWidgetCleanup(); - if ((windowType() == Qt::Popup)) + if ((windowType() == Qt::Popup) && qApp) qApp->d_func()->closePopup(this); if (this == QApplicationPrivate::active_window) diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index f65e52305c..b08eab580d 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -314,7 +314,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt return; } - if (d->transitionsEnabled() && canAnimate(option)) { + if ((option->state & State_Enabled) && d->transitionsEnabled() && canAnimate(option)) { { QRect oldRect; QRect newRect; diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index aaedd7ffee..fde46c9729 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -154,7 +154,7 @@ void QMenuPrivate::init() } platformMenu = QGuiApplicationPrivate::platformTheme()->createPlatformMenu(); - if (platformMenu) { + if (!platformMenu.isNull()) { QObject::connect(platformMenu, SIGNAL(aboutToShow()), q, SIGNAL(aboutToShow())); QObject::connect(platformMenu, SIGNAL(aboutToHide()), q, SIGNAL(aboutToHide())); } @@ -2411,7 +2411,7 @@ void QMenu::changeEvent(QEvent *e) if (d->tornPopup) // torn-off menu d->tornPopup->setEnabled(isEnabled()); d->menuAction->setEnabled(isEnabled()); - if (d->platformMenu) + if (!d->platformMenu.isNull()) d->platformMenu->setEnabled(isEnabled()); } QWidget::changeEvent(e); @@ -2992,7 +2992,7 @@ void QMenu::actionEvent(QActionEvent *e) d->widgetItems.remove(e->action()); } - if (d->platformMenu) { + if (!d->platformMenu.isNull()) { if (e->type() == QEvent::ActionAdded) { QPlatformMenuItem *menuItem = QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem(); @@ -3201,7 +3201,7 @@ void QMenu::setSeparatorsCollapsible(bool collapse) d->updateActionRects(); update(); } - if (d->platformMenu) + if (!d->platformMenu.isNull()) d->platformMenu->syncSeparatorsCollapsible(collapse); } diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h index 6cc88c56e2..15f3c92127 100644 --- a/src/widgets/widgets/qmenu_p.h +++ b/src/widgets/widgets/qmenu_p.h @@ -101,7 +101,8 @@ public: ~QMenuPrivate() { delete scroll; - delete platformMenu; + if (!platformMenu.isNull() && !platformMenu->parent()) + delete platformMenu.data(); #if defined(Q_OS_WINCE) && !defined(QT_NO_MENUBAR) delete wce_menu; #endif @@ -228,7 +229,7 @@ public: //menu fading/scrolling effects bool doChildEffects; - QPlatformMenu *platformMenu; + QPointer<QPlatformMenu> platformMenu; QPointer<QAction> actionAboutToTrigger; |