diff options
Diffstat (limited to 'src')
84 files changed, 2056 insertions, 1051 deletions
diff --git a/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro b/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro index 1bfeabb8c4..5ec86bf78f 100644 --- a/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro +++ b/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro @@ -11,7 +11,7 @@ load(qt_helper_lib) SHAPERS += opentype # HB's main shaper; enabling it should be enough most of the time # native shaper on Apple platforms; could be used alone to handle both OT and AAT fonts -darwin:!if(watchos:CONFIG(simulator, simulator|device)): SHAPERS += coretext +darwin: SHAPERS += coretext DEFINES += HAVE_CONFIG_H DEFINES += HB_NO_UNICODE_FUNCS HB_DISABLE_DEPRECATED @@ -155,4 +155,14 @@ contains(SHAPERS, coretext) { # On Mac OS they are part of the ApplicationServices umbrella framework, # even in 10.8 where they were also made available stand-alone. LIBS_PRIVATE += -framework ApplicationServices + + # CoreText is documented to be available on watchOS, but the headers aren't present + # in the watchOS Simulator SDK like they are supposed to be. Work around the problem + # by adding the device SDK's headers to the search path as a fallback. + # rdar://25314492, rdar://27844864 + watchos:CONFIG(simulator, simulator|device) { + QMAKE_CXXFLAGS += \ + -F$$xcodeSDKInfo(Path, $${simulator.sdk})/System/Library/Frameworks \ + -F$$xcodeSDKInfo(Path, $${device.sdk})/System/Library/Frameworks + } } diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index 6a8948822c..afcd20a9c1 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -2,6 +2,8 @@ HEADERS += \ global/qglobal.h \ + global/qoperatingsystemversion.h \ + global/qoperatingsystemversion_p.h \ global/qsystemdetection.h \ global/qcompilerdetection.h \ global/qprocessordetection.h \ @@ -27,11 +29,15 @@ SOURCES += \ global/qlibraryinfo.cpp \ global/qmalloc.cpp \ global/qnumeric.cpp \ + global/qoperatingsystemversion.cpp \ global/qlogging.cpp \ global/qhooks.cpp VERSIONTAGGING_SOURCES = global/qversiontagging.cpp +darwin: SOURCES += global/qoperatingsystemversion_darwin.mm +win32: SOURCES += global/qoperatingsystemversion_win.cpp + # qlibraryinfo.cpp includes qconfig.cpp INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 743d9d14a5..c78e6f2482 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -45,6 +45,8 @@ #include "qthreadstorage.h" #include "qdir.h" #include "qdatetime.h" +#include "qoperatingsystemversion.h" +#include "qoperatingsystemversion_p.h" #include <private/qlocale_tools_p.h> #include <qmutex.h> @@ -1088,12 +1090,14 @@ bool qSharedBuild() Q_DECL_NOTHROW */ /*! + \deprecated \variable QSysInfo::WindowsVersion \brief the version of the Windows operating system on which the application is run. */ /*! + \deprecated \fn QSysInfo::WindowsVersion QSysInfo::windowsVersion() \since 4.4 @@ -1103,12 +1107,14 @@ bool qSharedBuild() Q_DECL_NOTHROW */ /*! + \deprecated \variable QSysInfo::MacintoshVersion \brief the version of the Macintosh operating system on which the application is run. */ /*! + \deprecated \fn QSysInfo::MacVersion QSysInfo::macVersion() Returns the version of Darwin (\macos or iOS) on which the @@ -1126,6 +1132,7 @@ bool qSharedBuild() Q_DECL_NOTHROW */ /*! + \deprecated \enum QSysInfo::WinVersion This enum provides symbolic names for the various versions of the @@ -1182,6 +1189,7 @@ bool qSharedBuild() Q_DECL_NOTHROW */ /*! + \deprecated \enum QSysInfo::MacVersion This enum provides symbolic names for the various versions of the @@ -1943,28 +1951,31 @@ QT_BEGIN_INCLUDE_NAMESPACE #include "qnamespace.h" QT_END_INCLUDE_NAMESPACE +#if QT_DEPRECATED_SINCE(5, 9) QSysInfo::MacVersion QSysInfo::macVersion() { - const QAppleOperatingSystemVersion version = qt_apple_os_version(); // qtcore_mac_objc.mm + const auto version = QOperatingSystemVersion::current(); #if defined(Q_OS_OSX) - return QSysInfo::MacVersion(Q_MV_OSX(version.major, version.minor)); + return QSysInfo::MacVersion(Q_MV_OSX(version.majorVersion(), version.minorVersion())); #elif defined(Q_OS_IOS) - return QSysInfo::MacVersion(Q_MV_IOS(version.major, version.minor)); + return QSysInfo::MacVersion(Q_MV_IOS(version.majorVersion(), version.minorVersion())); #elif defined(Q_OS_TVOS) - return QSysInfo::MacVersion(Q_MV_TVOS(version.major, version.minor)); + return QSysInfo::MacVersion(Q_MV_TVOS(version.majorVersion(), version.minorVersion())); #elif defined(Q_OS_WATCHOS) - return QSysInfo::MacVersion(Q_MV_WATCHOS(version.major, version.minor)); + return QSysInfo::MacVersion(Q_MV_WATCHOS(version.majorVersion(), version.minorVersion())); #else return QSysInfo::MV_Unknown; #endif } const QSysInfo::MacVersion QSysInfo::MacintoshVersion = QSysInfo::macVersion(); +#endif -#ifdef Q_OS_OSX -static const char *osxVer_helper(QAppleOperatingSystemVersion version = qt_apple_os_version()) +#ifdef Q_OS_DARWIN +static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current()) { - if (version.major == 10) { - switch (version.minor) { +#ifdef Q_OS_MACOS + if (version.majorVersion() == 10) { + switch (version.minorVersion()) { case 9: return "Mavericks"; case 10: @@ -1976,6 +1987,9 @@ static const char *osxVer_helper(QAppleOperatingSystemVersion version = qt_apple } } // unknown, future version +#else + Q_UNUSED(version); +#endif return 0; } #endif @@ -2016,140 +2030,30 @@ QWindowsSockInit::~QWindowsSockInit() Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit) # endif // QT_BOOTSTRAPPED -#ifdef Q_OS_WINRT -static inline HMODULE moduleHandleForFunction(LPCVOID address) -{ - // This is a widely used, decades-old technique for retrieving the handle - // of a module and is effectively equivalent to GetModuleHandleEx - // (which is unavailable on WinRT) - MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 }; - if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0) - return 0; - return reinterpret_cast<HMODULE>(mbi.AllocationBase); -} -#endif - -static inline OSVERSIONINFOEX determineWinOsVersion() -{ - OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0}; - -#define GetProcAddressA GetProcAddress - - // GetModuleHandle is not supported in WinRT and linking to it at load time - // will not pass the Windows App Certification Kit... but it exists and is functional, - // so use some unusual but widely used techniques to get a pointer to it -#ifdef Q_OS_WINRT - // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL - HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery)); - if (Q_UNLIKELY(!kernelModule)) - return result; - - // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs) - typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR); - GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>( - GetProcAddressA(kernelModule, "GetModuleHandleW")); - if (Q_UNLIKELY(!pGetModuleHandle)) - return result; -#else -#define pGetModuleHandle GetModuleHandleW -#endif - -#ifndef Q_OS_WINCE - HMODULE ntdll = pGetModuleHandle(L"ntdll.dll"); - if (Q_UNLIKELY(!ntdll)) - return result; - - // NTSTATUS is not defined on WinRT - typedef LONG NTSTATUS; - typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO); - - // RtlGetVersion is documented public API but we must load it dynamically - // because linking to it at load time will not pass the Windows App Certification Kit - // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx - RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>( - GetProcAddressA(ntdll, "RtlGetVersion")); - if (Q_UNLIKELY(!pRtlGetVersion)) - return result; - - // GetVersionEx() has been deprecated in Windows 8.1 and will return - // only Windows 8 from that version on, so use the kernel API function. - pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS -#else // !Q_OS_WINCE - GetVersionEx(&result); -#endif - return result; -} - -static OSVERSIONINFOEX winOsVersion() -{ - OSVERSIONINFOEX realResult = determineWinOsVersion(); -#ifdef QT_DEBUG - { - if (Q_UNLIKELY(qEnvironmentVariableIsSet("QT_WINVER_OVERRIDE"))) { - OSVERSIONINFOEX result = realResult; - result.dwMajorVersion = 0; - result.dwMinorVersion = 0; - - // Erase any build number and service pack information - result.dwBuildNumber = 0; - result.szCSDVersion[0] = L'\0'; - result.wServicePackMajor = 0; - result.wServicePackMinor = 0; - - const QByteArray winVerOverride = qgetenv("QT_WINVER_OVERRIDE"); - if (winVerOverride == "WINDOWS7" || winVerOverride == "2008_R2") { - result.dwMajorVersion = 6; - result.dwMinorVersion = 1; - } else if (winVerOverride == "WINDOWS8" || winVerOverride == "2012") { - result.dwMajorVersion = 6; - result.dwMinorVersion = 2; - } else if (winVerOverride == "WINDOWS8_1" || winVerOverride == "2012_R2") { - result.dwMajorVersion = 6; - result.dwMinorVersion = 3; - } else if (winVerOverride == "WINDOWS10" || winVerOverride == "2016") { - result.dwMajorVersion = 10; - } else { - return realResult; - } - - if (winVerOverride == "2008_R2" - || winVerOverride == "2012" - || winVerOverride == "2012_R2" - || winVerOverride == "2016") { - // If the current host OS is a domain controller and the override OS - // is also a server type OS, preserve that information - if (result.wProductType == VER_NT_WORKSTATION) - result.wProductType = VER_NT_SERVER; - } else { - // Any other OS must be a workstation OS type - result.wProductType = VER_NT_WORKSTATION; - } - } - } -#endif - return realResult; -} - +#if QT_DEPRECATED_SINCE(5, 9) QSysInfo::WinVersion QSysInfo::windowsVersion() { - const OSVERSIONINFOEX osver = winOsVersion(); - if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1) + const auto version = QOperatingSystemVersion::current(); + if (version.majorVersion() == 6 && version.minorVersion() == 1) return QSysInfo::WV_WINDOWS7; - if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2) + if (version.majorVersion() == 6 && version.minorVersion() == 2) return QSysInfo::WV_WINDOWS8; - if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3) + if (version.majorVersion() == 6 && version.minorVersion() == 3) return QSysInfo::WV_WINDOWS8_1; - if (osver.dwMajorVersion == 10 && osver.dwMinorVersion == 0) + if (version.majorVersion() == 10 && version.minorVersion() == 0) return QSysInfo::WV_WINDOWS10; return QSysInfo::WV_NT_based; } +const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion(); +#endif static QString winSp_helper() { - const qint16 major = winOsVersion().wServicePackMajor; + const auto osv = qWindowsVersionInfo(); + const qint16 major = osv.wServicePackMajor; if (major) { QString sp = QStringLiteral(" SP ") + QString::number(major); - const qint16 minor = winOsVersion().wServicePackMinor; + const qint16 minor = osv.wServicePackMinor; if (minor) sp += QLatin1Char('.') + QString::number(minor); @@ -2158,9 +2062,10 @@ static QString winSp_helper() return QString(); } -static const char *winVer_helper() +static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current()) { - const OSVERSIONINFOEX osver = winOsVersion(); + Q_UNUSED(version); + const OSVERSIONINFOEX osver = qWindowsVersionInfo(); const bool workstation = osver.wProductType == VER_NT_WORKSTATION; #define Q_WINVER(major, minor) (major << 8 | minor) @@ -2179,8 +2084,6 @@ static const char *winVer_helper() return 0; } -const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion(); - #endif #if defined(Q_OS_UNIX) # if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD) @@ -2361,6 +2264,67 @@ static bool findUnixOsVersion(QUnixOSVersion &v) # endif // USE_ETC_OS_RELEASE #endif // Q_OS_UNIX +#ifdef Q_OS_ANDROID +static const char *osVer_helper(QOperatingSystemVersion) +{ +/* Data: + + + +Cupcake +Donut +Eclair +Eclair +Eclair +Froyo +Gingerbread +Gingerbread +Honeycomb +Honeycomb +Honeycomb +Ice Cream Sandwich +Ice Cream Sandwich +Jelly Bean +Jelly Bean +Jelly Bean +KitKat +KitKat +Lollipop +Lollipop +Marshmallow +Nougat + */ + static const char versions_string[] = + "\0" + "Cupcake\0" + "Donut\0" + "Eclair\0" + "Froyo\0" + "Gingerbread\0" + "Honeycomb\0" + "Ice Cream Sandwich\0" + "Jelly Bean\0" + "KitKat\0" + "Lollipop\0" + "Marshmallow\0" + "Nougat\0" + "\0"; + + static const int versions_indices[] = { + 0, 0, 0, 1, 9, 15, 15, 15, + 22, 28, 28, 40, 40, 40, 50, 50, + 69, 69, 69, 80, 80, 87, 87, 96, + 108, -1 + }; + + static const int versions_count = (sizeof versions_indices) / (sizeof versions_indices[0]); + + // https://source.android.com/source/build-numbers.html + // https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels + const int sdk_int = QJNIObjectPrivate::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT"); + return &versions_string[versions_indices[qBound(0, sdk_int, versions_count - 1)]]; +} +#endif /*! \since 5.4 @@ -2609,9 +2573,9 @@ QString QSysInfo::kernelType() QString QSysInfo::kernelVersion() { #ifdef Q_OS_WIN - const OSVERSIONINFOEX osver = winOsVersion(); - return QString::number(int(osver.dwMajorVersion)) + QLatin1Char('.') + QString::number(int(osver.dwMinorVersion)) - + QLatin1Char('.') + QString::number(int(osver.dwBuildNumber)); + const auto osver = QOperatingSystemVersion::current(); + return QString::number(osver.majorVersion()) + QLatin1Char('.') + QString::number(osver.minorVersion()) + + QLatin1Char('.') + QString::number(osver.microVersion()); #else struct utsname u; if (uname(&u) == 0) @@ -2679,8 +2643,8 @@ QString QSysInfo::productType() #elif defined(Q_OS_WATCHOS) return QStringLiteral("watchos"); #elif defined(Q_OS_MACOS) - const QAppleOperatingSystemVersion version = qt_apple_os_version(); - if (version.major == 10 && version.minor < 12) + const auto version = QOperatingSystemVersion::current(); + if (version.majorVersion() == 10 && version.minorVersion() < 12) return QStringLiteral("osx"); return QStringLiteral("macos"); #elif defined(Q_OS_DARWIN) @@ -2720,20 +2684,17 @@ QString QSysInfo::productType() */ QString QSysInfo::productVersion() { -#if defined(Q_OS_MAC) - const QAppleOperatingSystemVersion version = qt_apple_os_version(); - return QString::number(version.major) + QLatin1Char('.') + QString::number(version.minor); +#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) + const auto version = QOperatingSystemVersion::current(); + return QString::number(version.majorVersion()) + QLatin1Char('.') + QString::number(version.minorVersion()); #elif defined(Q_OS_WIN) - const char *version = winVer_helper(); + const char *version = osVer_helper(); if (version) { const QLatin1Char spaceChar(' '); return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower(); } // fall through -// Android should not fall through to the Unix code -#elif defined(Q_OS_ANDROID) - return QJNIObjectPrivate::getStaticObjectField("android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString(); #elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX QUnixOSVersion unixOsVersion; findUnixOsVersion(unixOsVersion); @@ -2761,44 +2722,23 @@ QString QSysInfo::productVersion() */ QString QSysInfo::prettyProductName() { -#if defined(Q_OS_IOS) - return QLatin1String("iOS ") + productVersion(); -#elif defined(Q_OS_TVOS) - return QLatin1String("tvOS ") + productVersion(); -#elif defined(Q_OS_WATCHOS) - return QLatin1String("watchOS ") + productVersion(); -#elif defined(Q_OS_MACOS) - const QAppleOperatingSystemVersion version = qt_apple_os_version(); - const char *name = osxVer_helper(version); - if (name) { - return (version.major == 10 && version.minor < 12 - ? QLatin1String("OS X ") - : QLatin1String("macOS ")) - + QLatin1String(name) - + QLatin1String(" (") + QString::number(version.major) - + QLatin1Char('.') + QString::number(version.minor) - + QLatin1Char(')'); - } else { - return QLatin1String("macOS ") - + QString::number(version.major) + QLatin1Char('.') - + QString::number(version.minor); - } -#elif defined(Q_OS_WINPHONE) - return QLatin1String("Windows Phone ") + QLatin1String(winVer_helper()); -#elif defined(Q_OS_WIN) - const char *name = winVer_helper(); - const OSVERSIONINFOEX osver = winOsVersion(); +#if defined(Q_OS_WINPHONE) + return QLatin1String("Windows Phone ") + QLatin1String(osVer_helper()); +#elif defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN) + const auto version = QOperatingSystemVersion::current(); + const char *name = osVer_helper(version); if (name) - return QLatin1String("Windows ") + QLatin1String(name) + winSp_helper() - + QLatin1String(" (") + QString::number(osver.dwMajorVersion) - + QLatin1Char('.') + QString::number(osver.dwMinorVersion) + return version.name() + QLatin1Char(' ') + QLatin1String(name) +# if defined(Q_OS_WIN) + + winSp_helper() +# endif + + QLatin1String(" (") + QString::number(version.majorVersion()) + + QLatin1Char('.') + QString::number(version.minorVersion()) + QLatin1Char(')'); - else - return QLatin1String("Windows ") - + QString::number(osver.dwMajorVersion) + QLatin1Char('.') - + QString::number(osver.dwMinorVersion); -#elif defined(Q_OS_ANDROID) - return QLatin1String("Android ") + productVersion(); + else + return version.name() + QLatin1Char(' ') + + QString::number(version.majorVersion()) + QLatin1Char('.') + + QString::number(version.minorVersion()); #elif defined(Q_OS_HAIKU) return QLatin1String("Haiku ") + productVersion(); #elif defined(Q_OS_UNIX) diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp new file mode 100644 index 0000000000..14dc109b3e --- /dev/null +++ b/src/corelib/global/qoperatingsystemversion.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qoperatingsystemversion.h" +#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN) +#include "qoperatingsystemversion_p.h" +#endif + +#include <qversionnumber.h> + +#if defined(Q_OS_ANDROID) +#include <private/qjni_p.h> +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QOperatingSystemVersion + \inmodule QtCore + \since 5.9 + \brief The QOperatingSystemVersion class provides information about the operating system version. + + Unlike other version functions in QSysInfo, QOperatingSystemVersion provides access to the full + version number that \a developers typically use to vary behavior or determine whether to enable + APIs or features based on the operating system version (as opposed to the kernel version number + or marketing version). + + This class is also a complete replacement for QSysInfo::macVersion and QSysInfo::windowsVersion, + additionally providing access to the third (micro) version number component. + + Presently, Android, Apple Platforms (iOS, macOS, tvOS, and watchOS), and Windows are supported. + + The \a majorVersion(), \a minorVersion(), and \a microVersion() functions return the parts of + the operating system version number based on: + + \table + \header \li Platforms \li Value + \row \li Android \li result of parsing + \l{https://developer.android.com/reference/android/os/Build.VERSION.html#RELEASE}{"android.os.Build.VERSION.RELEASE"} + using QVersionNumber, with a fallback to + \l{https://developer.android.com/reference/android/os/Build.VERSION.html#SDK_INT}{"android.os.Build.VERSION.SDK_INT"} + to determine the major and minor version component if the former fails + \row \li Apple Platforms \li majorVersion, minorVersion, and patchVersion from + \l{https://developer.apple.com/reference/foundation/nsprocessinfo/1410906-operatingsystemversion?language=objc}{"NSProcessInfo.operatingSystemVersion"} + \row \li Windows \li dwMajorVersion, dwMinorVersion, and dwBuildNumber from + \l{https://msdn.microsoft.com/en-us/library/mt723418.aspx}{"RtlGetVersion"} - + note that this function ALWAYS return the version number of the underlying operating system, + as opposed to the shim underneath GetVersionEx that hides the real version number + if the application is not manifested for that version of the OS + \endtable +*/ + +/*! + \fn QOperatingSystemVersion::QOperatingSystemVersion(int maj, int min, int mic) + + Constructs a QOperatingSystemVersion consisting of the OS type \a os, and + major, minor, and micro version numbers \a maj, \a min and \a mic, respectively. +*/ + +/*! + \fn QOperatingSystemVersion QOperatingSystemVersion::current() + + Returns a QOperatingSystemVersion indicating the current OS and its version number. +*/ +#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN) +QOperatingSystemVersion QOperatingSystemVersion::current() +{ + QOperatingSystemVersion version; + version.m_os = currentType(); +#if defined(Q_OS_ANDROID) +#ifndef QT_BOOTSTRAPPED + const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField( + "android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString()); + if (!v.isNull()) { + version.m_major = v.majorVersion(); + version.m_minor = v.minorVersion(); + version.m_micro = v.microVersion(); + return version; + } +#endif + + version.m_major = -1; + version.m_minor = -1; + + static const int versions[][2] = { + { 1, 0 }, // API level 1 + { 1, 1 }, // API level 2 + { 1, 5 }, // API level 3 + { 1, 6 }, // API level 4 + { 2, 0 }, // API level 5 + { 2, 0 }, // API level 6 + { 2, 1 }, // API level 7 + { 2, 2 }, // API level 8 + { 2, 3 }, // API level 9 + { 2, 3 }, // API level 10 + { 3, 0 }, // API level 11 + { 3, 1 }, // API level 12 + { 3, 2 }, // API level 13 + { 4, 0 }, // API level 14 + { 4, 0 }, // API level 15 + { 4, 1 }, // API level 16 + { 4, 2 }, // API level 17 + { 4, 3 }, // API level 18 + { 4, 4 }, // API level 19 + { 4, 4 }, // API level 20 + { 5, 0 }, // API level 21 + { 5, 1 }, // API level 22 + { 6, 0 }, // API level 23 + { 7, 0 }, // API level 24 + }; + + // This will give us at least the first 2 version components + const int sdk = static_cast<int>(QJNIObjectPrivate::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT")); + if (sdk >= 1 && sdk <= sizeof(versions) / sizeof(versions[0])) { + version.m_major = versions[sdk - 1][0]; + version.m_minor = versions[sdk - 1][1]; + } + + // API level 6 was exactly version 2.0.1 + version.m_micro = sdk == 6 ? 1 : -1; +#else + version.m_major = -1; + version.m_minor = -1; + version.m_micro = -1; +#endif + return version; +} +#endif + +static inline int compareVersionComponents(int lhs, int rhs) +{ + return lhs >= 0 && rhs >= 0 ? lhs - rhs : 0; +} + +/*! + \fn int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1, + const QOperatingSystemVersion &v2) + + Compares \a v1 with \a v2 and returns an integer less than, equal to, or + greater than zero, depending on whether \a v1 is less than, equal to, or + greater than \a v2, respectively. + + Comparisons are performed by comparing the version number components of + \a v1 and \a v2. + + \note This function cannot take the OS type into account; you should use + the overloaded comparison operators to compare QOperatingSystemVersions + in a safe manner. +*/ +int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1, const QOperatingSystemVersion &v2) +{ + if (v1.m_major == v2.m_major) { + if (v1.m_minor == v2.m_minor) { + return compareVersionComponents(v1.m_micro, v2.m_micro); + } + return compareVersionComponents(v1.m_minor, v2.m_minor); + } + return compareVersionComponents(v1.m_major, v2.m_major); +} + +#ifndef QT_BOOTSTRAPPED +/*! + \fn QOperatingSystemVersion QOperatingSystemVersion::fromVersionNumber(const QVersionNumber &version, + QOperatingSystemVersion::OSType os) + + Returns a QOperatingSystemVersion consisting of the OS type \a os and version number \a version. +*/ +QOperatingSystemVersion QOperatingSystemVersion::fromVersionNumber(const QVersionNumber &version, + QOperatingSystemVersion::OSType os) +{ + return QOperatingSystemVersion(os, version.majorVersion(), version.minorVersion(), version.microVersion()); +} + +/*! + \fn QOperatingSystemVersion QOperatingSystemVersion::toVersionNumber() const + + Returns the QOperatingSystemVersion's version number as a QVersionNumber. +*/ +QVersionNumber QOperatingSystemVersion::toVersionNumber() const +{ + return QVersionNumber(m_major, m_minor, m_micro); +} +#endif + +/*! + \fn int QOperatingSystemVersion::majorVersion() const + + Returns the major version number, that is, the first segment of the operating system's version number. + + See the main class documentation for what the major version number is on a given operating system. + + -1 indicates an unknown or absent version number component. + + \sa minorVersion(), microVersion() +*/ + +/*! + \fn int QOperatingSystemVersion::minorVersion() const + + Returns the minor version number, that is, the second segment of the operating system's version number. + + See the main class documentation for what the minor version number is on a given operating system. + + -1 indicates an unknown or absent version number component. + + \sa majorVersion(), macro() +*/ + +/*! + \fn int QOperatingSystemVersion::microVersion() const + + Returns the micro version number, that is, the third segment of the operating system's version number. + + See the main class documentation for what the micro version number is on a given operating system. + + -1 indicates an unknown or absent version number component. + + \sa majorVersion(), minorVersion() +*/ + +/*! + \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::type() const + + Returns the OS type identified by the QOperatingSystemVersion. + + \sa typeName() +*/ + +/*! + \fn QString QOperatingSystemVersion::name() const + + Returns a string representation of the OS type identified by the QOperatingSystemVersion. + + \sa type() +*/ +QString QOperatingSystemVersion::name() const +{ + switch (type()) { + case QOperatingSystemVersion::Windows: + return QStringLiteral("Windows"); + case QOperatingSystemVersion::MacOS: { + if (majorVersion() < 10) + return QStringLiteral("Mac OS"); + if (majorVersion() == 10 && minorVersion() < 8) + return QStringLiteral("Mac OS X"); + if (majorVersion() == 10 && minorVersion() < 12) + return QStringLiteral("OS X"); + return QStringLiteral("macOS"); + } + case QOperatingSystemVersion::IOS: { + if (majorVersion() < 4) + return QStringLiteral("iPhone OS"); + return QStringLiteral("iOS"); + } + case QOperatingSystemVersion::TvOS: + return QStringLiteral("tvOS"); + case QOperatingSystemVersion::WatchOS: + return QStringLiteral("watchOS"); + case QOperatingSystemVersion::Android: + return QStringLiteral("Android"); + case QOperatingSystemVersion::Unknown: + default: + return QString(); + } +} + +/*! + \variable QOperatingSystemVersion::Windows7 + \brief a version corresponding to Windows 7 (version 6.1). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::Windows7 = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 1); + +/*! + \variable QOperatingSystemVersion::Windows8 + \brief a version corresponding to Windows 8 (version 6.2). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::Windows8 = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 2); + +/*! + \variable QOperatingSystemVersion::Windows8_1 + \brief a version corresponding to Windows 8.1 (version 6.3). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::Windows8_1 = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 3); + +/*! + \variable QOperatingSystemVersion::Windows10 + \brief a version corresponding to Windows 10 (version 10.0). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::Windows10 = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10); + +/*! + \variable QOperatingSystemVersion::OSXMavericks + \brief a version corresponding to OS X Mavericks (version 10.9). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::OSXMavericks = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 9); + +/*! + \variable QOperatingSystemVersion::OSXYosemite + \brief a version corresponding to OS X Yosemite (version 10.10). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::OSXYosemite = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 10); + +/*! + \variable QOperatingSystemVersion::OSXElCapitan + \brief a version corresponding to OS X El Capitan (version 10.11). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::OSXElCapitan = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 11); + +/*! + \variable QOperatingSystemVersion::MacOSSierra + \brief a version corresponding to macOS Sierra (version 10.12). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::MacOSSierra = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 12); + +/*! + \variable QOperatingSystemVersion::AndroidJellyBean + \brief a version corresponding to Android Jelly Bean (versions 4.1 - 4.3). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean = QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 1); + +/*! + \variable QOperatingSystemVersion::AndroidKitKat + \brief a version corresponding to Android KitKat (version 4.4). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::AndroidKitKat = QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 4); + +/*! + \variable QOperatingSystemVersion::AndroidLollipop + \brief a version corresponding to Android Lollipop (versions 5.0 - 5.1). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop = QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 0); + +/*! + \variable QOperatingSystemVersion::AndroidMarshmallow + \brief a version corresponding to Android Marshmallow (version 6.0). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::AndroidMarshmallow = QOperatingSystemVersion(QOperatingSystemVersion::Android, 6); + +/*! + \variable QOperatingSystemVersion::AndroidNougat + \brief a version corresponding to Android Nougat (version 7.0). + \since 5.9 + */ +const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat = QOperatingSystemVersion(QOperatingSystemVersion::Android, 7); + +QT_END_NAMESPACE diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h new file mode 100644 index 0000000000..33c3d33bcc --- /dev/null +++ b/src/corelib/global/qoperatingsystemversion.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qglobal.h> + +#ifndef QOPERATINGSYSTEMVERSION_H +#define QOPERATINGSYSTEMVERSION_H + +QT_BEGIN_NAMESPACE + +class QString; +class QVersionNumber; + +class Q_CORE_EXPORT QOperatingSystemVersion +{ +public: + enum OSType { + Unknown = 0, + Windows, + MacOS, + IOS, + TvOS, + WatchOS, + Android + }; + + static const QOperatingSystemVersion Windows7; + static const QOperatingSystemVersion Windows8; + static const QOperatingSystemVersion Windows8_1; + static const QOperatingSystemVersion Windows10; + + static const QOperatingSystemVersion OSXMavericks; + static const QOperatingSystemVersion OSXYosemite; + static const QOperatingSystemVersion OSXElCapitan; + static const QOperatingSystemVersion MacOSSierra; + + static const QOperatingSystemVersion AndroidJellyBean; + static const QOperatingSystemVersion AndroidKitKat; + static const QOperatingSystemVersion AndroidLollipop; + static const QOperatingSystemVersion AndroidMarshmallow; + static const QOperatingSystemVersion AndroidNougat; + + QOperatingSystemVersion(const QOperatingSystemVersion &other) = default; + Q_DECL_CONSTEXPR QOperatingSystemVersion(OSType osType, int vmajor, int vminor = -1, int vmicro = -1) + : m_os(osType), m_major(vmajor), m_minor(vminor), m_micro(vmicro) { } + + static QOperatingSystemVersion current(); + + static int compare(const QOperatingSystemVersion &v1, const QOperatingSystemVersion &v2); + + QOperatingSystemVersion fromVersionNumber(const QVersionNumber &version, OSType os); + QVersionNumber toVersionNumber() const; + + Q_DECL_CONSTEXPR int majorVersion() const { return m_major; } + Q_DECL_CONSTEXPR int minorVersion() const { return m_minor; } + Q_DECL_CONSTEXPR int microVersion() const { return m_micro; } + + Q_DECL_CONSTEXPR OSType type() const { return m_os; } + QString name() const; + +private: + QOperatingSystemVersion() = default; + OSType m_os; + int m_major; + int m_minor; + int m_micro; +}; + +inline bool operator>(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs) +{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) > 0; } + +inline bool operator>=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs) +{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) >= 0; } + +inline bool operator<(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs) +{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) < 0; } + +inline bool operator<=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs) +{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) <= 0; } + +inline bool operator==(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs) +{ return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) == 0; } + +inline bool operator!=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs) +{ return !(lhs == rhs); } + +QT_END_NAMESPACE + +#endif // QOPERATINGSYSTEMVERSION_H diff --git a/src/corelib/global/qoperatingsystemversion_darwin.mm b/src/corelib/global/qoperatingsystemversion_darwin.mm new file mode 100644 index 0000000000..3dd007cbb3 --- /dev/null +++ b/src/corelib/global/qoperatingsystemversion_darwin.mm @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qoperatingsystemversion_p.h" +#import <Foundation/Foundation.h> + +#ifdef Q_OS_IOS +#import <UIKit/UIKit.h> +#endif + +QT_BEGIN_NAMESPACE + +typedef qint16 (*GestaltFunction)(quint32 selector, qint32 *response); + +QOperatingSystemVersion QOperatingSystemVersion::current() +{ + QOperatingSystemVersion v; + v.m_os = currentType(); + v.m_major = -1; + v.m_minor = -1; + v.m_micro = -1; +#if QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_8_0) || defined(Q_OS_TVOS) || defined(Q_OS_WATCHOS) + if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) { + NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion; + v.m_major = osv.majorVersion; + v.m_minor = osv.minorVersion; + v.m_micro = osv.patchVersion; + return v; + } +#endif + // Use temporary variables so we can return 0.0.0 (unknown version) + // in case of an error partway through determining the OS version + qint32 major = 0, minor = 0, patch = 0; +#if QT_MACOS_IOS_DEPLOYMENT_TARGET_BELOW(__MAC_10_10, __IPHONE_8_0) +#if defined(Q_OS_IOS) + @autoreleasepool { + NSArray *parts = [UIDevice.currentDevice.systemVersion componentsSeparatedByString:@"."]; + major = parts.count > 0 ? [[parts objectAtIndex:0] intValue] : 0; + minor = parts.count > 1 ? [[parts objectAtIndex:1] intValue] : 0; + patch = parts.count > 2 ? [[parts objectAtIndex:2] intValue] : 0; + } +#elif defined(Q_OS_MACOS) + static GestaltFunction pGestalt = 0; + if (!pGestalt) { + CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreServices")); + pGestalt = reinterpret_cast<GestaltFunction>(CFBundleGetFunctionPointerForName(b, + CFSTR("Gestalt"))); + } + if (!pGestalt) + return v; + if (pGestalt('sys1', &major) != 0) + return v; + if (pGestalt('sys2', &minor) != 0) + return v; + if (pGestalt('sys3', &patch) != 0) + return v; +#endif +#endif + v.m_major = major; + v.m_minor = minor; + v.m_micro = patch; + return v; +} + +QT_END_NAMESPACE diff --git a/src/corelib/global/qoperatingsystemversion_p.h b/src/corelib/global/qoperatingsystemversion_p.h new file mode 100644 index 0000000000..f227e98dd1 --- /dev/null +++ b/src/corelib/global/qoperatingsystemversion_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qoperatingsystemversion.h" + +#ifdef Q_OS_WIN +#include <qt_windows.h> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN +OSVERSIONINFOEX qWindowsVersionInfo(); +#endif + +static inline QOperatingSystemVersion::OSType currentType() +{ +#if defined(Q_OS_WIN) + return QOperatingSystemVersion::Windows; +#elif defined(Q_OS_MACOS) + return QOperatingSystemVersion::MacOS; +#elif defined(Q_OS_IOS) + return QOperatingSystemVersion::IOS; +#elif defined(Q_OS_TVOS) + return QOperatingSystemVersion::TvOS; +#elif defined(Q_OS_WATCHOS) + return QOperatingSystemVersion::WatchOS; +#elif defined(Q_OS_ANDROID) + return QOperatingSystemVersion::Android; +#else + return QOperatingSystemVersion::Unknown; +#endif +} + +QT_END_NAMESPACE diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp new file mode 100644 index 0000000000..060ca2f7da --- /dev/null +++ b/src/corelib/global/qoperatingsystemversion_win.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qoperatingsystemversion_p.h" +#include <qt_windows.h> +#include <qbytearray.h> + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WINRT +static inline HMODULE moduleHandleForFunction(LPCVOID address) +{ + // This is a widely used, decades-old technique for retrieving the handle + // of a module and is effectively equivalent to GetModuleHandleEx + // (which is unavailable on WinRT) + MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 }; + if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0) + return 0; + return reinterpret_cast<HMODULE>(mbi.AllocationBase); +} +#endif + +static inline OSVERSIONINFOEX determineWinOsVersion() +{ + OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0}; + +#define GetProcAddressA GetProcAddress + + // GetModuleHandle is not supported in WinRT and linking to it at load time + // will not pass the Windows App Certification Kit... but it exists and is functional, + // so use some unusual but widely used techniques to get a pointer to it +#ifdef Q_OS_WINRT + // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL + HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery)); + if (Q_UNLIKELY(!kernelModule)) + return result; + + // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs) + typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR); + GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>( + GetProcAddressA(kernelModule, "GetModuleHandleW")); + if (Q_UNLIKELY(!pGetModuleHandle)) + return result; +#else +#define pGetModuleHandle GetModuleHandleW +#endif + +#ifndef Q_OS_WINCE + HMODULE ntdll = pGetModuleHandle(L"ntdll.dll"); + if (Q_UNLIKELY(!ntdll)) + return result; + + // NTSTATUS is not defined on WinRT + typedef LONG NTSTATUS; + typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO); + + // RtlGetVersion is documented public API but we must load it dynamically + // because linking to it at load time will not pass the Windows App Certification Kit + // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx + RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>( + GetProcAddressA(ntdll, "RtlGetVersion")); + if (Q_UNLIKELY(!pRtlGetVersion)) + return result; + + // GetVersionEx() has been deprecated in Windows 8.1 and will return + // only Windows 8 from that version on, so use the kernel API function. + pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS +#else // !Q_OS_WINCE + GetVersionEx(&result); +#endif + return result; +} + +OSVERSIONINFOEX qWindowsVersionInfo() +{ + OSVERSIONINFOEX realResult = determineWinOsVersion(); +#ifdef QT_DEBUG + { + if (Q_UNLIKELY(qEnvironmentVariableIsSet("QT_WINVER_OVERRIDE"))) { + OSVERSIONINFOEX result = realResult; + result.dwMajorVersion = 0; + result.dwMinorVersion = 0; + + // Erase any build number and service pack information + result.dwBuildNumber = 0; + result.szCSDVersion[0] = L'\0'; + result.wServicePackMajor = 0; + result.wServicePackMinor = 0; + + const QByteArray winVerOverride = qgetenv("QT_WINVER_OVERRIDE"); + if (winVerOverride == "WINDOWS7" || winVerOverride == "2008_R2") { + result.dwMajorVersion = 6; + result.dwMinorVersion = 1; + } else if (winVerOverride == "WINDOWS8" || winVerOverride == "2012") { + result.dwMajorVersion = 6; + result.dwMinorVersion = 2; + } else if (winVerOverride == "WINDOWS8_1" || winVerOverride == "2012_R2") { + result.dwMajorVersion = 6; + result.dwMinorVersion = 3; + } else if (winVerOverride == "WINDOWS10" || winVerOverride == "2016") { + result.dwMajorVersion = 10; + } else { + return realResult; + } + + if (winVerOverride == "2008_R2" + || winVerOverride == "2012" + || winVerOverride == "2012_R2" + || winVerOverride == "2016") { + // If the current host OS is a domain controller and the override OS + // is also a server type OS, preserve that information + if (result.wProductType == VER_NT_WORKSTATION) + result.wProductType = VER_NT_SERVER; + } else { + // Any other OS must be a workstation OS type + result.wProductType = VER_NT_WORKSTATION; + } + } + } +#endif + return realResult; +} + +QOperatingSystemVersion QOperatingSystemVersion::current() +{ + QOperatingSystemVersion v; + v.m_os = currentType(); + const OSVERSIONINFOEX osv = qWindowsVersionInfo(); + v.m_major = osv.dwMajorVersion; + v.m_minor = osv.dwMinorVersion; + v.m_micro = osv.dwBuildNumber; + return v; +} + +QT_END_NAMESPACE diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h index 23f412aa6a..5ec55d467c 100644 --- a/src/corelib/global/qsysinfo.h +++ b/src/corelib/global/qsysinfo.h @@ -79,7 +79,8 @@ public: # endif }; #endif - enum WinVersion { +#if QT_DEPRECATED_SINCE(5, 9) + enum QT_DEPRECATED_X("Use QOperatingSystemVersion") WinVersion { WV_None = 0x0000, WV_32s = 0x0001, @@ -117,19 +118,25 @@ public: WV_CE_6 = 0x0400, WV_CE_based = 0x0f00 }; +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") +QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") +QT_WARNING_DISABLE_INTEL(1478) +QT_WARNING_DISABLE_MSVC(4996) #if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) - static const WinVersion WindowsVersion; - static WinVersion windowsVersion(); + QT_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const WinVersion WindowsVersion; + QT_DEPRECATED_X("Use QOperatingSystemVersion::current()") static WinVersion windowsVersion(); #else - static const WinVersion WindowsVersion = WV_None; - static WinVersion windowsVersion() { return WV_None; } + QT_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const WinVersion WindowsVersion = WV_None; + QT_DEPRECATED_X("Use QOperatingSystemVersion::current()") static WinVersion windowsVersion() { return WV_None; } #endif +QT_WARNING_POP #define Q_MV_OSX(major, minor) (major == 10 ? minor + 2 : (major == 9 ? 1 : 0)) #define Q_MV_IOS(major, minor) (QSysInfo::MV_IOS | major << 4 | minor) #define Q_MV_TVOS(major, minor) (QSysInfo::MV_TVOS | major << 4 | minor) #define Q_MV_WATCHOS(major, minor) (QSysInfo::MV_WATCHOS | major << 4 | minor) - enum MacVersion { + enum QT_DEPRECATED_X("Use QOperatingSystemVersion") MacVersion { MV_None = 0xffff, MV_Unknown = 0x0000, @@ -198,13 +205,20 @@ public: MV_WATCHOS_2_2 = Q_MV_WATCHOS(2, 2), MV_WATCHOS_3_0 = Q_MV_WATCHOS(3, 0) }; +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations") +QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") +QT_WARNING_DISABLE_INTEL(1478) +QT_WARNING_DISABLE_MSVC(4996) #if defined(Q_OS_MAC) - static const MacVersion MacintoshVersion; - static MacVersion macVersion(); + QT_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const MacVersion MacintoshVersion; + QT_DEPRECATED_X("Use QOperatingSystemVersion::current()") static MacVersion macVersion(); #else - static const MacVersion MacintoshVersion = MV_None; - static MacVersion macVersion() { return MV_None; } + QT_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const MacVersion MacintoshVersion = MV_None; + QT_DEPRECATED_X("Use QOperatingSystemVersion::current()") static MacVersion macVersion() { return MV_None; } #endif +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(5, 9) static QString buildCpuArchitecture(); static QString currentCpuArchitecture(); diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index ac58677b77..994ed88791 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -95,10 +95,11 @@ public: Qt_5_6 = 17, Qt_5_7 = Qt_5_6, Qt_5_8 = Qt_5_7, -#if QT_VERSION >= 0x050900 + Qt_5_9 = Qt_5_8, +#if QT_VERSION >= 0x050a00 #error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion #endif - Qt_DefaultCompiledVersion = Qt_5_8 + Qt_DefaultCompiledVersion = Qt_5_9 }; enum ByteOrder { @@ -222,6 +223,98 @@ private: QDataStream::Status oldStatus; }; +template <typename Container> +QDataStream &readArrayBasedContainer(QDataStream &s, Container &c) +{ + StreamStateSaver stateSaver(&s); + + c.clear(); + quint32 n; + s >> n; + c.reserve(n); + for (quint32 i = 0; i < n; ++i) { + typename Container::value_type t; + s >> t; + if (s.status() != QDataStream::Ok) { + c.clear(); + break; + } + c.append(t); + } + + return s; +} + +template <typename Container> +QDataStream &readListBasedContainer(QDataStream &s, Container &c) +{ + StreamStateSaver stateSaver(&s); + + c.clear(); + quint32 n; + s >> n; + for (quint32 i = 0; i < n; ++i) { + typename Container::value_type t; + s >> t; + if (s.status() != QDataStream::Ok) { + c.clear(); + break; + } + c << t; + } + + return s; +} + +template <typename Container> +QDataStream &readAssociativeContainer(QDataStream &s, Container &c) +{ + StreamStateSaver stateSaver(&s); + + c.clear(); + quint32 n; + s >> n; + for (quint32 i = 0; i < n; ++i) { + typename Container::key_type k; + typename Container::mapped_type t; + s >> k >> t; + if (s.status() != QDataStream::Ok) { + c.clear(); + break; + } + c.insertMulti(k, t); + } + + return s; +} + +template <typename Container> +QDataStream &writeSequentialContainer(QDataStream &s, const Container &c) +{ + s << quint32(c.size()); + for (const typename Container::value_type &t : c) + s << t; + + return s; +} + +template <typename Container> +QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c) +{ + s << quint32(c.size()); + // Deserialization should occur in the reverse order. + // Otherwise, value() will return the least recently inserted + // value instead of the most recently inserted one. + auto it = c.constEnd(); + auto begin = c.constBegin(); + while (it != begin) { + --it; + s << it.key() << it.value(); + } + + return s; +} + } // QtPrivate namespace /***************************************************************************** @@ -265,209 +358,75 @@ inline QDataStream &QDataStream::operator<<(quint64 i) { return *this << qint64(i); } template <typename T> -QDataStream& operator>>(QDataStream& s, QList<T>& l) +inline QDataStream &operator>>(QDataStream &s, QList<T> &l) { - QtPrivate::StreamStateSaver stateSaver(&s); - - l.clear(); - quint32 c; - s >> c; - l.reserve(c); - for(quint32 i = 0; i < c; ++i) - { - T t; - s >> t; - if (s.status() != QDataStream::Ok) { - l.clear(); - break; - } - l.append(t); - } - - return s; + return QtPrivate::readArrayBasedContainer(s, l); } template <typename T> -QDataStream& operator<<(QDataStream& s, const QList<T>& l) +inline QDataStream &operator<<(QDataStream &s, const QList<T> &l) { - s << quint32(l.size()); - for (int i = 0; i < l.size(); ++i) - s << l.at(i); - return s; + return QtPrivate::writeSequentialContainer(s, l); } template <typename T> -QDataStream& operator>>(QDataStream& s, QLinkedList<T>& l) +inline QDataStream &operator>>(QDataStream &s, QLinkedList<T> &l) { - QtPrivate::StreamStateSaver stateSaver(&s); - - l.clear(); - quint32 c; - s >> c; - for(quint32 i = 0; i < c; ++i) - { - T t; - s >> t; - if (s.status() != QDataStream::Ok) { - l.clear(); - break; - } - l.append(t); - } - - return s; + return QtPrivate::readListBasedContainer(s, l); } template <typename T> -QDataStream& operator<<(QDataStream& s, const QLinkedList<T>& l) +inline QDataStream &operator<<(QDataStream &s, const QLinkedList<T> &l) { - s << quint32(l.size()); - typename QLinkedList<T>::ConstIterator it = l.constBegin(); - for(; it != l.constEnd(); ++it) - s << *it; - return s; + return QtPrivate::writeSequentialContainer(s, l); } template<typename T> -QDataStream& operator>>(QDataStream& s, QVector<T>& v) +inline QDataStream &operator>>(QDataStream &s, QVector<T> &v) { - QtPrivate::StreamStateSaver stateSaver(&s); - - v.clear(); - quint32 c; - s >> c; - v.resize(c); - for(quint32 i = 0; i < c; ++i) { - T t; - s >> t; - if (s.status() != QDataStream::Ok) { - v.clear(); - break; - } - v[i] = t; - } - - return s; + return QtPrivate::readArrayBasedContainer(s, v); } template<typename T> -QDataStream& operator<<(QDataStream& s, const QVector<T>& v) +inline QDataStream &operator<<(QDataStream &s, const QVector<T> &v) { - s << quint32(v.size()); - for (typename QVector<T>::const_iterator it = v.begin(); it != v.end(); ++it) - s << *it; - return s; + return QtPrivate::writeSequentialContainer(s, v); } template <typename T> -QDataStream &operator>>(QDataStream &in, QSet<T> &set) +inline QDataStream &operator>>(QDataStream &s, QSet<T> &set) { - QtPrivate::StreamStateSaver stateSaver(&in); - - set.clear(); - quint32 c; - in >> c; - for (quint32 i = 0; i < c; ++i) { - T t; - in >> t; - if (in.status() != QDataStream::Ok) { - set.clear(); - break; - } - set << t; - } - - return in; + return QtPrivate::readListBasedContainer(s, set); } template <typename T> -QDataStream& operator<<(QDataStream &out, const QSet<T> &set) +inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set) { - out << quint32(set.size()); - typename QSet<T>::const_iterator i = set.constBegin(); - while (i != set.constEnd()) { - out << *i; - ++i; - } - return out; + return QtPrivate::writeSequentialContainer(s, set); } template <class Key, class T> -Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash<Key, T> &hash) +inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash) { - QtPrivate::StreamStateSaver stateSaver(&in); - - hash.clear(); - quint32 n; - in >> n; - - for (quint32 i = 0; i < n; ++i) { - if (in.status() != QDataStream::Ok) - break; - - Key k; - T t; - in >> k >> t; - hash.insertMulti(k, t); - } - - if (in.status() != QDataStream::Ok) - hash.clear(); - return in; + return QtPrivate::readAssociativeContainer(s, hash); } template <class Key, class T> -Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash) +inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash) { - out << quint32(hash.size()); - typename QHash<Key, T>::ConstIterator it = hash.end(); - typename QHash<Key, T>::ConstIterator begin = hash.begin(); - while (it != begin) { - --it; - out << it.key() << it.value(); - } - return out; + return QtPrivate::writeAssociativeContainer(s, hash); } -#ifdef Q_QDOC + template <class Key, class T> -Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<Key, T> &map) -#else -template <class aKey, class aT> -Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<aKey, aT> &map) -#endif +inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map) { - QtPrivate::StreamStateSaver stateSaver(&in); - - map.clear(); - quint32 n; - in >> n; - - map.detach(); - for (quint32 i = 0; i < n; ++i) { - if (in.status() != QDataStream::Ok) - break; - - aKey key; - aT value; - in >> key >> value; - map.insertMulti(key, value); - } - if (in.status() != QDataStream::Ok) - map.clear(); - return in; + return QtPrivate::readAssociativeContainer(s, map); } template <class Key, class T> -Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map) +inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map) { - out << quint32(map.size()); - typename QMap<Key, T>::ConstIterator it = map.end(); - typename QMap<Key, T>::ConstIterator begin = map.begin(); - while (it != begin) { - --it; - out << it.key() << it.value(); - } - return out; + return QtPrivate::writeAssociativeContainer(s, map); } #ifndef QT_NO_DATASTREAM diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index cdb64d08e1..663d9cd61d 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -38,7 +38,7 @@ ****************************************************************************/ #include "qfilesystemengine_p.h" - +#include "qoperatingsystemversion.h" #include "qplatformdefs.h" #include "qsysinfo.h" #include "private/qabstractfileengine_p.h" @@ -637,7 +637,7 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry) FILE_SHARE_READ, OPEN_EXISTING, NULL); #endif // Q_OS_WINRT if (handle) { - result = QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8 ? + result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ? fileIdWin8(handle) : fileId(handle); CloseHandle(handle); } diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp index 2ce7bd7a4b..9140118872 100644 --- a/src/corelib/io/qfilesystemiterator_win.cpp +++ b/src/corelib/io/qfilesystemiterator_win.cpp @@ -39,6 +39,7 @@ #include "qfilesystemiterator_p.h" #include "qfilesystemengine_p.h" +#include "qoperatingsystemversion.h" #include "qplatformdefs.h" #include "qvector.h" @@ -93,7 +94,7 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa haveData = true; int infoLevel = 0 ; // FindExInfoStandard; DWORD dwAdditionalFlags = 0; - if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows7) { dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH infoLevel = 1 ; // FindExInfoBasic; } diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index fcdc1e362b..b67afe0e0f 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -136,7 +136,18 @@ Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE); typedef QHash<QString, QConfFile *> ConfFileHash; typedef QCache<QString, QConfFile> ConfFileCache; -typedef QHash<int, QString> PathHash; +namespace { + struct Path + { + // Note: Defining constructors explicitly because of buggy C++11 + // implementation in MSVC (uniform initialization). + Path() {} + Path(const QString & p, bool ud) : path(p), userDefined(ud) {} + QString path; + bool userDefined; //!< true - user defined, overridden by setPath + }; +} +typedef QHash<int, Path> PathHash; typedef QVector<QConfFileCustomFormat> CustomFormatVector; Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc) @@ -228,7 +239,7 @@ void QConfFile::clearCache() // QSettingsPrivate QSettingsPrivate::QSettingsPrivate(QSettings::Format format) - : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), spec(0), fallbacks(true), + : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError) { } @@ -236,7 +247,7 @@ QSettingsPrivate::QSettingsPrivate(QSettings::Format format) QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application) : format(format), scope(scope), organizationName(organization), applicationName(application), - iniCodec(0), spec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError) + iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError) { } @@ -944,7 +955,7 @@ void QConfFileSettingsPrivate::initFormat() void QConfFileSettingsPrivate::initAccess() { - if (confFiles[spec]) { + if (!confFiles.isEmpty()) { if (format > QSettings::IniFormat) { if (!readFunc) setStatus(QSettings::AccessError); @@ -1065,22 +1076,22 @@ static void initDefaultPaths(QMutexLocker *locker) */ #ifdef Q_OS_WIN pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), - windowsConfigPath(CSIDL_APPDATA) + QDir::separator()); + Path(windowsConfigPath(CSIDL_APPDATA) + QDir::separator(), false)); pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), - windowsConfigPath(CSIDL_COMMON_APPDATA) + QDir::separator()); + Path(windowsConfigPath(CSIDL_COMMON_APPDATA) + QDir::separator(), false)); #else const QString userPath = make_user_path(); - pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), userPath); - pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), systemPath); + pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false)); + pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false)); #ifndef Q_OS_MAC - pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), userPath); - pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), systemPath); + pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false)); + pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false)); #endif #endif // Q_OS_WIN } } -static QString getPath(QSettings::Format format, QSettings::Scope scope) +static Path getPath(QSettings::Format format, QSettings::Scope scope) { Q_ASSERT((int)QSettings::NativeFormat == 0); Q_ASSERT((int)QSettings::IniFormat == 1); @@ -1090,14 +1101,23 @@ static QString getPath(QSettings::Format format, QSettings::Scope scope) if (pathHash->isEmpty()) initDefaultPaths(&locker); - QString result = pathHash->value(pathHashKey(format, scope)); - if (!result.isEmpty()) + Path result = pathHash->value(pathHashKey(format, scope)); + if (!result.path.isEmpty()) return result; // fall back on INI path return pathHash->value(pathHashKey(QSettings::IniFormat, scope)); } +#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS) +// Note: Suitable only for autotests. +void Q_AUTOTEST_EXPORT clearDefaultPaths() +{ + QMutexLocker locker(&settingsGlobalMutex); + pathHashFunc()->clear(); +} +#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS + QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format, QSettings::Scope scope, const QString &organization, @@ -1105,7 +1125,6 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format, : QSettingsPrivate(format, scope, organization, application), nextPosition(0x40000000) // big positive number { - int i; initFormat(); QString org = organization; @@ -1118,22 +1137,43 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format, QString orgFile = org + extension; if (scope == QSettings::UserScope) { - QString userPath = getPath(format, QSettings::UserScope); + Path userPath = getPath(format, QSettings::UserScope); if (!application.isEmpty()) - confFiles[F_User | F_Application].reset(QConfFile::fromName(userPath + appFile, true)); - confFiles[F_User | F_Organization].reset(QConfFile::fromName(userPath + orgFile, true)); + confFiles.append(QConfFile::fromName(userPath.path + appFile, true)); + confFiles.append(QConfFile::fromName(userPath.path + orgFile, true)); } - QString systemPath = getPath(format, QSettings::SystemScope); - if (!application.isEmpty()) - confFiles[F_System | F_Application].reset(QConfFile::fromName(systemPath + appFile, false)); - confFiles[F_System | F_Organization].reset(QConfFile::fromName(systemPath + orgFile, false)); - - for (i = 0; i < NumConfFiles; ++i) { - if (confFiles[i]) { - spec = i; - break; + Path systemPath = getPath(format, QSettings::SystemScope); +#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS) + // check if the systemPath wasn't overridden by QSettings::setPath() + if (!systemPath.userDefined) { + // Note: We can't use QStandardPaths::locateAll() as we need all the + // possible files (not just the existing ones) and there is no way + // to exclude user specific (XDG_CONFIG_HOME) directory from the search. + QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation); + // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME) + if (!dirs.isEmpty()) + dirs.takeFirst(); + QStringList paths; + if (!application.isEmpty()) { + paths.reserve(dirs.size() * 2); + for (const auto &dir : qAsConst(dirs)) + paths.append(dir + QLatin1Char('/') + appFile); + } else { + paths.reserve(dirs.size()); } + for (const auto &dir : qAsConst(dirs)) + paths.append(dir + QLatin1Char('/') + orgFile); + + // Note: No check for existence of files is done intentionaly. + for (const auto &path : qAsConst(paths)) + confFiles.append(QConfFile::fromName(path, false)); + } else +#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS + { + if (!application.isEmpty()) + confFiles.append(QConfFile::fromName(systemPath.path + appFile, false)); + confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false)); } initAccess(); @@ -1146,7 +1186,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName, { initFormat(); - confFiles[0].reset(QConfFile::fromName(fileName, true)); + confFiles.append(QConfFile::fromName(fileName, true)); initAccess(); } @@ -1157,40 +1197,39 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate() ConfFileHash *usedHash = usedHashFunc(); ConfFileCache *unusedCache = unusedCacheFunc(); - for (int i = 0; i < NumConfFiles; ++i) { - if (confFiles[i] && !confFiles[i]->ref.deref()) { - if (confFiles[i]->size == 0) { - delete confFiles[i].take(); + for (auto conf_file : qAsConst(confFiles)) { + if (!conf_file->ref.deref()) { + if (conf_file->size == 0) { + delete conf_file; } else { if (usedHash) - usedHash->remove(confFiles[i]->name); + usedHash->remove(conf_file->name); if (unusedCache) { QT_TRY { // compute a better size? - unusedCache->insert(confFiles[i]->name, confFiles[i].data(), - 10 + (confFiles[i]->originalKeys.size() / 4)); - confFiles[i].take(); + unusedCache->insert(conf_file->name, conf_file, + 10 + (conf_file->originalKeys.size() / 4)); } QT_CATCH(...) { // out of memory. Do not cache the file. - delete confFiles[i].take(); + delete conf_file; } } else { // unusedCache is gone - delete the entry to prevent a memory leak - delete confFiles[i].take(); + delete conf_file; } } } - // prevent the ScopedPointer to deref it again. - confFiles[i].take(); } } void QConfFileSettingsPrivate::remove(const QString &key) { - QConfFile *confFile = confFiles[spec].data(); - if (!confFile) + if (confFiles.isEmpty()) return; + // Note: First config file is always the most specific. + QConfFile *confFile = confFiles.at(0); + QSettingsKey theKey(key, caseSensitivity); QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity); QMutexLocker locker(&confFile->mutex); @@ -1214,10 +1253,12 @@ void QConfFileSettingsPrivate::remove(const QString &key) void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value) { - QConfFile *confFile = confFiles[spec].data(); - if (!confFile) + if (confFiles.isEmpty()) return; + // Note: First config file is always the most specific. + QConfFile *confFile = confFiles.at(0); + QSettingsKey theKey(key, caseSensitivity, nextPosition++); QMutexLocker locker(&confFile->mutex); confFile->removedKeys.remove(theKey); @@ -1230,29 +1271,27 @@ bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const ParsedSettingsMap::const_iterator j; bool found = false; - for (int i = 0; i < NumConfFiles; ++i) { - if (QConfFile *confFile = confFiles[i].data()) { - QMutexLocker locker(&confFile->mutex); + for (auto confFile : qAsConst(confFiles)) { + QMutexLocker locker(&confFile->mutex); - if (!confFile->addedKeys.isEmpty()) { - j = confFile->addedKeys.constFind(theKey); - found = (j != confFile->addedKeys.constEnd()); - } - if (!found) { - ensureSectionParsed(confFile, theKey); - j = confFile->originalKeys.constFind(theKey); - found = (j != confFile->originalKeys.constEnd() - && !confFile->removedKeys.contains(theKey)); - } + if (!confFile->addedKeys.isEmpty()) { + j = confFile->addedKeys.constFind(theKey); + found = (j != confFile->addedKeys.constEnd()); + } + if (!found) { + ensureSectionParsed(confFile, theKey); + j = confFile->originalKeys.constFind(theKey); + found = (j != confFile->originalKeys.constEnd() + && !confFile->removedKeys.contains(theKey)); + } - if (found && value) - *value = *j; + if (found && value) + *value = *j; - if (found) - return true; - if (!fallbacks) - break; - } + if (found) + return true; + if (!fallbacks) + break; } return false; } @@ -1265,34 +1304,31 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec QSettingsKey thePrefix(prefix, caseSensitivity); int startPos = prefix.size(); - for (int i = 0; i < NumConfFiles; ++i) { - if (QConfFile *confFile = confFiles[i].data()) { - QMutexLocker locker(&confFile->mutex); + for (auto confFile : qAsConst(confFiles)) { + QMutexLocker locker(&confFile->mutex); - if (thePrefix.isEmpty()) { - ensureAllSectionsParsed(confFile); - } else { - ensureSectionParsed(confFile, thePrefix); - } - - j = const_cast<const ParsedSettingsMap *>( - &confFile->originalKeys)->lowerBound( thePrefix); - while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) { - if (!confFile->removedKeys.contains(j.key())) - processChild(j.key().originalCaseKey().midRef(startPos), spec, result); - ++j; - } + if (thePrefix.isEmpty()) + ensureAllSectionsParsed(confFile); + else + ensureSectionParsed(confFile, thePrefix); - j = const_cast<const ParsedSettingsMap *>( - &confFile->addedKeys)->lowerBound(thePrefix); - while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) { + j = const_cast<const ParsedSettingsMap *>( + &confFile->originalKeys)->lowerBound( thePrefix); + while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) { + if (!confFile->removedKeys.contains(j.key())) processChild(j.key().originalCaseKey().midRef(startPos), spec, result); - ++j; - } + ++j; + } - if (!fallbacks) - break; + j = const_cast<const ParsedSettingsMap *>( + &confFile->addedKeys)->lowerBound(thePrefix); + while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) { + processChild(j.key().originalCaseKey().midRef(startPos), spec, result); + ++j; } + + if (!fallbacks) + break; } std::sort(result.begin(), result.end()); result.erase(std::unique(result.begin(), result.end()), @@ -1302,10 +1338,12 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec void QConfFileSettingsPrivate::clear() { - QConfFile *confFile = confFiles[spec].data(); - if (!confFile) + if (confFiles.isEmpty()) return; + // Note: First config file is always the most specific. + QConfFile *confFile = confFiles.at(0); + QMutexLocker locker(&confFile->mutex); ensureAllSectionsParsed(confFile); confFile->addedKeys.clear(); @@ -1317,12 +1355,9 @@ void QConfFileSettingsPrivate::sync() // people probably won't be checking the status a whole lot, so in case of // error we just try to go on and make the best of it - for (int i = 0; i < NumConfFiles; ++i) { - QConfFile *confFile = confFiles[i].data(); - if (confFile) { - QMutexLocker locker(&confFile->mutex); - syncConfFile(i); - } + for (auto confFile : qAsConst(confFiles)) { + QMutexLocker locker(&confFile->mutex); + syncConfFile(confFile); } } @@ -1333,10 +1368,11 @@ void QConfFileSettingsPrivate::flush() QString QConfFileSettingsPrivate::fileName() const { - QConfFile *confFile = confFiles[spec].data(); - if (!confFile) + if (confFiles.isEmpty()) return QString(); - return confFile->name; + + // Note: First config file is always the most specific. + return confFiles.at(0)->name; } bool QConfFileSettingsPrivate::isWritable() const @@ -1344,16 +1380,14 @@ bool QConfFileSettingsPrivate::isWritable() const if (format > QSettings::IniFormat && !writeFunc) return false; - QConfFile *confFile = confFiles[spec].data(); - if (!confFile) + if (confFiles.isEmpty()) return false; - return confFile->isWritable(); + return confFiles.at(0)->isWritable(); } -void QConfFileSettingsPrivate::syncConfFile(int confFileNo) +void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) { - QConfFile *confFile = confFiles[confFileNo].data(); bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty(); /* @@ -2183,9 +2217,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \list 1 \li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf}) \li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf}) - \li \c{/etc/xdg/MySoft/Star Runner.conf} - \li \c{/etc/xdg/MySoft.conf} + \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf} + \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf} \endlist + \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used. On \macos versions 10.2 and 10.3, these files are used by default: @@ -2220,9 +2255,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \list 1 \li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini}) \li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini}) - \li \c{/etc/xdg/MySoft/Star Runner.ini} - \li \c{/etc/xdg/MySoft.ini} + \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini} + \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini} \endlist + \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used. On Windows, the following files are used: @@ -3374,7 +3410,7 @@ void QSettings::setPath(Format format, Scope scope, const QString &path) PathHash *pathHash = pathHashFunc(); if (pathHash->isEmpty()) initDefaultPaths(&locker); - pathHash->insert(pathHashKey(format, scope), path + QDir::separator()); + pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true)); } /*! diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp index bc397055ff..4ad5a7b398 100644 --- a/src/corelib/io/qsettings_mac.cpp +++ b/src/corelib/io/qsettings_mac.cpp @@ -419,20 +419,15 @@ QMacSettingsPrivate::QMacSettingsPrivate(QSettings::Scope scope, const QString & javaPackageName.prepend(QLatin1String("com.")); suiteId = javaPackageName; - if (scope == QSettings::SystemScope) - spec |= F_System; - - if (application.isEmpty()) { - spec |= F_Organization; - } else { + if (!application.isEmpty()) { javaPackageName += QLatin1Char('.'); javaPackageName += application; applicationId = javaPackageName; } numDomains = 0; - for (int i = (spec & F_System) ? 1 : 0; i < 2; ++i) { - for (int j = (spec & F_Organization) ? 1 : 0; j < 3; ++j) { + for (int i = (scope == QSettings::SystemScope) ? 1 : 0; i < 2; ++i) { + for (int j = (application.isEmpty()) ? 1 : 0; j < 3; ++j) { SearchDomain &domain = domains[numDomains++]; domain.userName = (i == 0) ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser; if (j == 0) @@ -573,7 +568,7 @@ bool QMacSettingsPrivate::isWritable() const QString QMacSettingsPrivate::fileName() const { QString result; - if ((spec & F_System) == 0) + if (scope == QSettings::UserScope) result = QDir::homePath(); result += QLatin1String("/Library/Preferences/"); result += QCFString::toQString(domains[0].applicationOrSuiteId); diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index e6d3413bab..639605d8c4 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -236,19 +236,6 @@ public: QTextCodec *codec); static QStringList splitArgs(const QString &s, int idx); - /* - The numeric values of these enums define their search order. For example, - F_User | F_Organization is searched before F_System | F_Application, - because their values are respectively 1 and 2. - */ - enum { - F_Application = 0x0, - F_Organization = 0x1, - F_User = 0x0, - F_System = 0x2, - NumConfFiles = 4 - }; - QSettings::Format format; QSettings::Scope scope; QString organizationName; @@ -258,7 +245,6 @@ public: protected: QStack<QSettingsGroup> groupStack; QString groupPrefix; - int spec; bool fallbacks; bool pendingChanges; mutable QSettings::Status status; @@ -293,7 +279,7 @@ public: private: void initFormat(); void initAccess(); - void syncConfFile(int confFileNo); + void syncConfFile(QConfFile *confFile); bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map); #ifdef Q_OS_MAC bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const; @@ -302,7 +288,7 @@ private: void ensureAllSectionsParsed(QConfFile *confFile) const; void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const; - QScopedSharedPointer<QConfFile> confFiles[NumConfFiles]; + QVector<QConfFile *> confFiles; QSettings::ReadFunc readFunc; QSettings::WriteFunc writeFunc; QString extension; diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp index 3773b72606..9885da1af9 100644 --- a/src/corelib/io/qstorageinfo.cpp +++ b/src/corelib/io/qstorageinfo.cpp @@ -260,7 +260,7 @@ QByteArray QStorageInfo::fileSystemType() const devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC path starting with \c \\\\?\\ for local storages (in other words, the volume GUID). - \sa rootPath() + \sa rootPath(), subvolume() */ QByteArray QStorageInfo::device() const { @@ -268,6 +268,26 @@ QByteArray QStorageInfo::device() const } /*! + \since 5.8 + Returns the subvolume name for this volume. + + Some filesystem types allow multiple subvolumes inside one device, which + may be mounted in different paths. If the subvolume could be detected, it + is returned here. The format of the subvolume name is specific to each + filesystem type. + + If this volume was not mounted from a subvolume of a larger filesystem or + if the subvolume could not be detected, this function returns an empty byte + array. + + \sa device() +*/ +QByteArray QStorageInfo::subvolume() const +{ + return d->subvolume; +} + +/*! Returns the human-readable name of a filesystem, usually called \c label. Not all filesystems support this feature. In this case, the value returned by diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h index 8941c11a16..e2d9747ceb 100644 --- a/src/corelib/io/qstorageinfo.h +++ b/src/corelib/io/qstorageinfo.h @@ -71,6 +71,7 @@ public: QString rootPath() const; QByteArray device() const; + QByteArray subvolume() const; QByteArray fileSystemType() const; QString name() const; QString displayName() const; @@ -100,7 +101,7 @@ inline bool operator==(const QStorageInfo &first, const QStorageInfo &second) { if (first.d == second.d) return true; - return first.device() == second.device(); + return first.device() == second.device() && first.rootPath() == second.rootPath(); } inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second) diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h index a14fa8480a..ec5bb785e3 100644 --- a/src/corelib/io/qstorageinfo_p.h +++ b/src/corelib/io/qstorageinfo_p.h @@ -85,6 +85,7 @@ protected: public: QString rootPath; QByteArray device; + QByteArray subvolume; QByteArray fileSystemType; QString name; diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index ae5c42ffd1..fcc7b8ca50 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -120,6 +120,7 @@ public: inline QString rootPath() const; inline QByteArray fileSystemType() const; inline QByteArray device() const; + inline QByteArray options() const; private: #if defined(Q_OS_BSD4) QT_STATFSBUF *stat_buf; @@ -133,6 +134,7 @@ private: QByteArray m_rootPath; QByteArray m_fileSystemType; QByteArray m_device; + QByteArray m_options; #elif defined(Q_OS_LINUX) || defined(Q_OS_HURD) FILE *fp; mntent mnt; @@ -228,6 +230,11 @@ inline QByteArray QStorageIterator::device() const return QByteArray(stat_buf[currentIndex].f_mntfromname); } +inline QByteArray QStorageIterator::options() const +{ + return QByteArray(); +} + #elif defined(Q_OS_SOLARIS) static const char pathMounted[] = "/etc/mnttab"; @@ -301,6 +308,7 @@ inline bool QStorageIterator::next() m_device = data.at(0); m_rootPath = data.at(1); m_fileSystemType = data.at(2); + m_options = data.at(3); return true; } @@ -320,6 +328,11 @@ inline QByteArray QStorageIterator::device() const return m_device; } +inline QByteArray QStorageIterator::options() const +{ + return m_options; +} + #elif defined(Q_OS_LINUX) || defined(Q_OS_HURD) static const char pathMounted[] = "/etc/mtab"; @@ -363,6 +376,11 @@ inline QByteArray QStorageIterator::device() const return QByteArray(mnt.mnt_fsname); } +inline QByteArray QStorageIterator::options() const +{ + return QByteArray(mnt.mnt_opts); +} + #elif defined(Q_OS_HAIKU) inline QStorageIterator::QStorageIterator() { @@ -420,6 +438,11 @@ inline QByteArray QStorageIterator::device() const return m_device; } +inline QByteArray QStorageIterator::options() const +{ + return QByteArray(); +} + #else inline QStorageIterator::QStorageIterator() @@ -455,8 +478,35 @@ inline QByteArray QStorageIterator::device() const return QByteArray(); } +inline QByteArray QStorageIterator::options() const +{ + return QByteArray(); +} + #endif +static QByteArray extractSubvolume(const QStorageIterator &it) +{ +#ifdef Q_OS_LINUX + if (it.fileSystemType() == "btrfs") { + const QByteArrayList opts = it.options().split(','); + QByteArray id; + for (const QByteArray &opt : opts) { + static const char subvol[] = "subvol="; + static const char subvolid[] = "subvolid="; + if (opt.startsWith(subvol)) + return std::move(opt).mid(strlen(subvol)); + if (opt.startsWith(subvolid)) + id = std::move(opt).mid(strlen(subvolid)); + } + + // if we didn't find the subvolume name, return the subvolume ID + return id; + } +#endif + return QByteArray(); +} + void QStorageInfoPrivate::initRootPath() { rootPath = QFileInfo(rootPath).canonicalFilePath(); @@ -483,6 +533,7 @@ void QStorageInfoPrivate::initRootPath() rootPath = mountDir; device = it.device(); fileSystemType = fsName; + subvolume = extractSubvolume(it); } } } diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp index 6e50a8513e..b2bf9fce97 100644 --- a/src/corelib/io/qtemporarydir.cpp +++ b/src/corelib/io/qtemporarydir.cpp @@ -305,6 +305,33 @@ QString QTemporaryDir::path() const } /*! + \since 5.9 + + Returns the path name of a file in the temporary directory. + Does \e not check if the file actually exists in the directory. + Redundant multiple separators or "." and ".." directories in + \a fileName are not removed (see QDir::cleanPath()). Absolute + paths are not allowed. +*/ +QString QTemporaryDir::filePath(const QString &fileName) const +{ + if (QDir::isAbsolutePath(fileName)) { + qWarning("QTemporaryDir::filePath: Absolute paths are not allowed: %s", qUtf8Printable(fileName)); + return QString(); + } + + if (!d_ptr->success) + return QString(); + + QString ret = d_ptr->pathOrError; + if (!fileName.isEmpty()) { + ret += QLatin1Char('/'); + ret += fileName; + } + return ret; +} + +/*! Returns \c true if the QTemporaryDir is in auto remove mode. Auto-remove mode will automatically delete the directory from disk upon destruction. This makes it very easy to create your diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h index 2e70d34ae4..3f6b70a2eb 100644 --- a/src/corelib/io/qtemporarydir.h +++ b/src/corelib/io/qtemporarydir.h @@ -65,6 +65,7 @@ public: bool remove(); QString path() const; + QString filePath(const QString &fileName) const; private: QScopedPointer<QTemporaryDirPrivate> d_ptr; diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 4fdb1505ff..9b565bff9d 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -2547,6 +2547,7 @@ QTextStream &QTextStream::operator<<(double f) } uint flags = 0; + const QLocale::NumberOptions numberOptions = locale().numberOptions(); if (numberFlags() & ShowBase) flags |= QLocaleData::ShowBase; if (numberFlags() & ForceSign) @@ -2555,12 +2556,18 @@ QTextStream &QTextStream::operator<<(double f) flags |= QLocaleData::UppercaseBase; if (numberFlags() & UppercaseDigits) flags |= QLocaleData::CapitalEorX; - if (numberFlags() & ForcePoint) - flags |= QLocaleData::Alternate; - if (locale() != QLocale::c() && !(locale().numberOptions() & QLocale::OmitGroupSeparator)) + if (numberFlags() & ForcePoint) { + flags |= QLocaleData::ForcePoint; + + // Only for backwards compatibility + flags |= QLocaleData::AddTrailingZeroes | QLocaleData::ShowBase; + } + if (locale() != QLocale::c() && !(numberOptions & QLocale::OmitGroupSeparator)) flags |= QLocaleData::ThousandsGroup; - if (!(locale().numberOptions() & QLocale::OmitLeadingZeroInExponent)) + if (!(numberOptions & QLocale::OmitLeadingZeroInExponent)) flags |= QLocaleData::ZeroPadExponent; + if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot) + flags |= QLocaleData::AddTrailingZeroes; const QLocaleData *dd = d->locale.d->m_data; QString num = dd->doubleToString(f, d->params.realNumberPrecision, form, -1, flags); diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index ee1a290386..42f5699928 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -47,14 +47,8 @@ #include <qdebug.h> -#if defined(Q_OS_IOS) -#import <UIKit/UIKit.h> -#endif - QT_BEGIN_NAMESPACE -typedef qint16 (*GestaltFunction)(quint32 selector, qint32 *response); - NSString *QCFString::toNSString(const QString &string) { // The const cast below is safe: CfStringRef is immutable and so is NSString. @@ -98,54 +92,6 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TY // ------------------------------------------------------------------------- -QAppleOperatingSystemVersion qt_apple_os_version() -{ - QAppleOperatingSystemVersion v = {0, 0, 0}; -#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_8_0) || defined(Q_OS_TVOS) || defined(Q_OS_WATCHOS) - if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) { - NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion; - v.major = osv.majorVersion; - v.minor = osv.minorVersion; - v.patch = osv.patchVersion; - return v; - } -#endif - // Use temporary variables so we can return 0.0.0 (unknown version) - // in case of an error partway through determining the OS version - qint32 major = 0, minor = 0, patch = 0; -#if QT_MAC_DEPLOYMENT_TARGET_BELOW(__MAC_10_10, __IPHONE_8_0) -#if defined(Q_OS_IOS) - @autoreleasepool { - NSArray *parts = [UIDevice.currentDevice.systemVersion componentsSeparatedByString:@"."]; - major = parts.count > 0 ? [[parts objectAtIndex:0] intValue] : 0; - minor = parts.count > 1 ? [[parts objectAtIndex:1] intValue] : 0; - patch = parts.count > 2 ? [[parts objectAtIndex:2] intValue] : 0; - } -#elif defined(Q_OS_OSX) - static GestaltFunction pGestalt = 0; - if (!pGestalt) { - CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreServices")); - pGestalt = reinterpret_cast<GestaltFunction>(CFBundleGetFunctionPointerForName(b, - CFSTR("Gestalt"))); - } - if (!pGestalt) - return v; - if (pGestalt('sys1', &major) != 0) - return v; - if (pGestalt('sys2', &minor) != 0) - return v; - if (pGestalt('sys3', &patch) != 0) - return v; -#endif -#endif - v.major = major; - v.minor = minor; - v.patch = patch; - return v; -} - -// ------------------------------------------------------------------------- - QMacAutoReleasePool::QMacAutoReleasePool() : pool([[NSAutoreleasePool alloc] init]) { diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 63e1cb48dc..8a710a8a1f 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -137,12 +137,6 @@ private: QString string; }; -typedef struct { - int major, minor, patch; -} QAppleOperatingSystemVersion; - -QAppleOperatingSystemVersion qt_apple_os_version(); - #ifdef Q_OS_OSX Q_CORE_EXPORT QChar qt_mac_qtKey2CocoaKey(Qt::Key key); Q_CORE_EXPORT Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode); diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 1a0efae2dc..ebeb083abf 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -42,6 +42,7 @@ #include "qcoreapplication.h" #include <private/qsystemlibrary_p.h> +#include "qoperatingsystemversion.h" #include "qpair.h" #include "qset.h" #include "qsocketnotifier.h" @@ -236,7 +237,7 @@ static inline UINT inputTimerMask() // QTBUG 28513, QTBUG-29097, QTBUG-29435: QS_TOUCH, QS_POINTER became part of // QS_INPUT in Windows Kit 8. They should not be used when running on pre-Windows 8. #if WINVER > 0x0601 - if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) result &= ~(QS_TOUCH | QS_POINTER); #endif // WINVER > 0x0601 return result; diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 63b02d2c0c..d7cc0bce46 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3943,7 +3943,6 @@ QList<QByteArray> QObject::dynamicPropertyNames() const static void dumpRecursive(int level, QObject *object) { -#if defined(QT_DEBUG) if (object) { QByteArray buf; buf.fill(' ', level / 2 * 8); @@ -3972,19 +3971,11 @@ static void dumpRecursive(int level, QObject *object) dumpRecursive(level+1, children.at(i)); } } -#else - Q_UNUSED(level) - Q_UNUSED(object) -#endif } /*! Dumps a tree of children to the debug output. - This function is useful for debugging, but does nothing if the - library has been compiled in release mode (i.e. without debugging - information). - \sa dumpObjectInfo() */ @@ -3997,16 +3988,11 @@ void QObject::dumpObjectTree() Dumps information about signal connections, etc. for this object to the debug output. - This function is useful for debugging, but does nothing if the - library has been compiled in release mode (i.e. without debugging - information). - \sa dumpObjectTree() */ void QObject::dumpObjectInfo() { -#if defined(QT_DEBUG) qDebug("OBJECT %s::%s", metaObject()->className(), objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data()); @@ -4066,7 +4052,6 @@ void QObject::dumpObjectInfo() } else { qDebug(" <None>"); } -#endif } #ifndef QT_NO_USERDATA diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index 55af7256be..a04536b18b 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -63,6 +63,29 @@ QT_WARNING_POP static const QArrayData &qt_array_empty = qt_array[0]; static const QArrayData &qt_array_unsharable_empty = qt_array[1]; +static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize, + uint options) +{ + // Calculate the byte size + // allocSize = objectSize * capacity + headerSize, but checked for overflow + // plus padded to grow in size + if (options & QArrayData::Grow) { + auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize); + capacity = r.elementCount; + return r.size; + } else { + return qCalculateBlockSize(capacity, objectSize, headerSize); + } +} + +static QArrayData *reallocateData(QArrayData *header, size_t allocSize, uint options) +{ + header = static_cast<QArrayData *>(::realloc(header, allocSize)); + if (header) + header->capacityReserved = bool(options & QArrayData::CapacityReserved); + return header; +} + QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, size_t capacity, AllocationOptions options) Q_DECL_NOTHROW { @@ -91,18 +114,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, if (headerSize > size_t(MaxAllocSize)) return 0; - // Calculate the byte size - // allocSize = objectSize * capacity + headerSize, but checked for overflow - // plus padded to grow in size - size_t allocSize; - if (options & Grow) { - auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize); - capacity = r.elementCount; - allocSize = r.size; - } else { - allocSize = qCalculateBlockSize(capacity, objectSize, headerSize); - } - + size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize)); if (header) { quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1) @@ -122,6 +134,21 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, return header; } +QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity, + AllocationOptions options) Q_DECL_NOTHROW +{ + Q_ASSERT(data); + Q_ASSERT(data->isMutable()); + Q_ASSERT(!data->ref.isShared()); + + size_t headerSize = sizeof(QArrayData); + size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options); + QArrayData *header = static_cast<QArrayData *>(reallocateData(data, allocSize, options)); + if (header) + header->alloc = capacity; + return header; +} + void QArrayData::deallocate(QArrayData *data, size_t objectSize, size_t alignment) Q_DECL_NOTHROW { diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 5a369baf08..bc20932cca 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -115,6 +115,9 @@ struct Q_CORE_EXPORT QArrayData static QArrayData *allocate(size_t objectSize, size_t alignment, size_t capacity, AllocationOptions options = Default) Q_DECL_NOTHROW Q_REQUIRED_RESULT; + static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize, + size_t newCapacity, AllocationOptions newOptions = Default) + Q_DECL_NOTHROW Q_REQUIRED_RESULT; static void deallocate(QArrayData *data, size_t objectSize, size_t alignment) Q_DECL_NOTHROW; @@ -222,6 +225,14 @@ struct QTypedArrayData Q_ALIGNOF(AlignmentDummy), capacity, options)); } + static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity, + AllocationOptions options = Default) + { + Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); + return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T), + capacity, options)); + } + static void deallocate(QArrayData *data) { Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData)); diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 9298472305..7d9c5dc325 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -663,6 +663,20 @@ QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel) */ #ifndef QT_NO_COMPRESS +namespace { +struct QByteArrayDataDeleter +{ + static inline void cleanup(QTypedArrayData<char> *d) + { if (d) QTypedArrayData<char>::deallocate(d); } +}; +} + +static QByteArray invalidCompressedData() +{ + qWarning("qUncompress: Input data is corrupted"); + return QByteArray(); +} + QByteArray qUncompress(const uchar* data, int nbytes) { if (!data) { @@ -677,53 +691,29 @@ QByteArray qUncompress(const uchar* data, int nbytes) ulong expectedSize = uint((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3] )); ulong len = qMax(expectedSize, 1ul); - QScopedPointer<QByteArray::Data, QScopedPointerPodDeleter> d; + const ulong maxPossibleSize = MaxAllocSize - sizeof(QByteArray::Data); + if (Q_UNLIKELY(len >= maxPossibleSize)) { + // QByteArray does not support that huge size anyway. + return invalidCompressedData(); + } + QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(QByteArray::Data::allocate(expectedSize + 1)); + if (Q_UNLIKELY(d.data() == nullptr)) + return invalidCompressedData(); + + d->size = expectedSize; forever { ulong alloc = len; - if (len >= (1u << 31u) - sizeof(QByteArray::Data)) { - //QByteArray does not support that huge size anyway. - qWarning("qUncompress: Input data is corrupted"); - return QByteArray(); - } - QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(d.data(), sizeof(QByteArray::Data) + alloc + 1)); - if (!p) { - // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS - qWarning("qUncompress: could not allocate enough memory to uncompress data"); - return QByteArray(); - } - d.take(); // realloc was successful - d.reset(p); - d->offset = sizeof(QByteArrayData); - d->size = 0; // Shut up valgrind "uninitialized variable" warning int res = ::uncompress((uchar*)d->data(), &len, data+4, nbytes-4); switch (res) { case Z_OK: - if (len != alloc) { - if (len >= (1u << 31u) - sizeof(QByteArray::Data)) { - //QByteArray does not support that huge size anyway. - qWarning("qUncompress: Input data is corrupted"); - return QByteArray(); - } - QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(d.data(), sizeof(QByteArray::Data) + len + 1)); - if (!p) { - // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS - qWarning("qUncompress: could not allocate enough memory to uncompress data"); - return QByteArray(); - } - d.take(); // realloc was successful - d.reset(p); - } - d->ref.initializeOwned(); + Q_ASSERT(len <= alloc); + Q_UNUSED(alloc); d->size = len; - d->alloc = uint(len) + 1u; - d->capacityReserved = false; - d->offset = sizeof(QByteArrayData); d->data()[len] = 0; - { QByteArrayDataPtr dataPtr = { d.take() }; return QByteArray(dataPtr); @@ -735,6 +725,17 @@ QByteArray qUncompress(const uchar* data, int nbytes) case Z_BUF_ERROR: len *= 2; + if (Q_UNLIKELY(len >= maxPossibleSize)) { + // QByteArray does not support that huge size anyway. + return invalidCompressedData(); + } else { + // grow the block + QByteArray::Data *p = QByteArray::Data::reallocateUnaligned(d.data(), len + 1); + if (Q_UNLIKELY(p == nullptr)) + return invalidCompressedData(); + d.take(); // don't free + d.reset(p); + } continue; case Z_DATA_ERROR: @@ -1707,19 +1708,8 @@ void QByteArray::reallocData(uint alloc, Data::AllocationOptions options) Data::deallocate(d); d = x; } else { - size_t blockSize; - if (options & Data::Grow) { - auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data)); - blockSize = r.size; - alloc = uint(r.elementCount); - } else { - blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data)); - } - - Data *x = static_cast<Data *>(::realloc(d, blockSize)); + Data *x = Data::reallocateUnaligned(d, alloc, options); Q_CHECK_PTR(x); - x->alloc = alloc; - x->capacityReserved = (options & Data::CapacityReserved) ? 1 : 0; d = x; } } diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index f8611b3e68..ac8054ce82 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -926,7 +926,7 @@ QString QDate::toString(Qt::DateFormat format) const */ QString QDate::toString(const QString& format) const { - return QLocale::system().toString(*this, format); + return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6 } #endif //QT_NO_DATESTRING @@ -1330,6 +1330,7 @@ QDate QDate::fromString(const QString &string, const QString &format) QDate date; #ifndef QT_BOOTSTRAPPED QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); + // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format)) dt.fromString(string, &date, 0); #else @@ -1666,7 +1667,7 @@ QString QTime::toString(Qt::DateFormat format) const */ QString QTime::toString(const QString& format) const { - return QLocale::system().toString(*this, format); + return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6 } #endif //QT_NO_DATESTRING /*! @@ -2018,6 +2019,7 @@ QTime QTime::fromString(const QString &string, const QString &format) QTime time; #ifndef QT_BOOTSTRAPPED QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); + // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format)) dt.fromString(string, 0, &time); #else @@ -3881,7 +3883,7 @@ QString QDateTime::toString(Qt::DateFormat format) const */ QString QDateTime::toString(const QString& format) const { - return QLocale::system().toString(*this, format); + return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6 } #endif //QT_NO_DATESTRING @@ -4934,6 +4936,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format) QDate date; QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString); + // dt.setDefaultLocale(QLocale::c()); ### Qt 6 if (dt.parseFormat(format) && dt.fromString(string, &date, &time)) return QDateTime(date, time); #else diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 7809c513d6..c25ee5ffbe 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -2024,6 +2024,8 @@ QString QLocale::toString(double i, char f, int prec) const flags |= QLocaleData::ThousandsGroup; if (!(d->m_numberOptions & OmitLeadingZeroInExponent)) flags |= QLocaleData::ZeroPadExponent; + if (d->m_numberOptions & IncludeTrailingZeroesAfterDot) + flags |= QLocaleData::AddTrailingZeroes; return d->m_data->doubleToString(i, prec, form, -1, flags); } @@ -2785,7 +2787,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q reinterpret_cast<ushort *>(digits.data())[i] += z; } - bool always_show_decpt = (flags & Alternate || flags & ForcePoint); + bool always_show_decpt = (flags & ForcePoint); switch (form) { case DFExponent: { num_str = exponentForm(_zero, decimal, exponential, group, plus, minus, @@ -2800,7 +2802,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q break; } case DFSignificantDigits: { - PrecisionMode mode = (flags & Alternate) ? + PrecisionMode mode = (flags & AddTrailingZeroes) ? PMSignificantDigits : PMChopTrailingZeros; int cutoff = precision < 0 ? 6 : precision; @@ -2905,7 +2907,7 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group, for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i) num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); - if ((flags & Alternate || flags & ShowBase) + if ((flags & ShowBase) && base == 8 && (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0'))) num_str.prepend(QLatin1Char('0')); @@ -2926,10 +2928,10 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group, --num_pad_chars; // leave space for optional '0x' in hex form - if (base == 16 && (flags & Alternate || flags & ShowBase)) + if (base == 16 && (flags & ShowBase)) num_pad_chars -= 2; // leave space for optional '0b' in binary form - else if (base == 2 && (flags & Alternate || flags & ShowBase)) + else if (base == 2 && (flags & ShowBase)) num_pad_chars -= 2; for (int i = 0; i < num_pad_chars; ++i) @@ -2939,9 +2941,9 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group, if (flags & CapitalEorX) num_str = num_str.toUpper(); - if (base == 16 && (flags & Alternate || flags & ShowBase)) + if (base == 16 && (flags & ShowBase)) num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x")); - if (base == 2 && (flags & Alternate || flags & ShowBase)) + if (base == 2 && (flags & ShowBase)) num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b")); // add sign @@ -2988,7 +2990,7 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group, for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i) num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0')); - if ((flags & Alternate || flags & ShowBase) + if ((flags & ShowBase) && base == 8 && (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0'))) num_str.prepend(QLatin1Char('0')); @@ -3003,10 +3005,10 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group, int num_pad_chars = width - num_str.length(); // leave space for optional '0x' in hex form - if (base == 16 && flags & Alternate) + if (base == 16 && flags & ShowBase) num_pad_chars -= 2; // leave space for optional '0b' in binary form - else if (base == 2 && flags & Alternate) + else if (base == 2 && flags & ShowBase) num_pad_chars -= 2; for (int i = 0; i < num_pad_chars; ++i) @@ -3016,9 +3018,9 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group, if (flags & CapitalEorX) num_str = num_str.toUpper(); - if (base == 16 && (flags & Alternate || flags & ShowBase)) + if (base == 16 && flags & ShowBase) num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x")); - else if (base == 2 && (flags & Alternate || flags & ShowBase)) + else if (base == 2 && flags & ShowBase) num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b")); // add sign @@ -3079,25 +3081,37 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti out = in.toLatin1(); else break; + } else if (out == '.') { + // Fail if more than one decimal point or point after e + if (decpt_idx != -1 || exponent_idx != -1) + return false; + decpt_idx = idx; + } else if (out == 'e' || out == 'E') { + exponent_idx = idx; } if (number_options & QLocale::RejectLeadingZeroInExponent) { - if (out == 'e' || out == 'E') { - exponent_idx = idx; - } else if (exponent_idx != -1) { - if (out >= '1' && out <= '9') - exponent_idx = -1; // leading digit is not 0, forget exponent_idx - else if (out == '0' && idx < l - 1) + if (exponent_idx != -1 && out == '0' && idx < l - 1) { + // After the exponent there can only be '+', '-' or digits. + // If we find a '0' directly after some non-digit, then that is a leading zero. + if (result->last() < '0' || result->last() > '9') return false; } } + if (number_options & QLocale::RejectTrailingZeroesAfterDot) { + // If we've seen a decimal point and the last character after the exponent is 0, then + // that is a trailing zero. + if (decpt_idx >= 0 && idx == exponent_idx && result->last() == '0') + return false; + } + if (!(number_options & QLocale::RejectGroupSeparator)) { if (start_of_digits_idx == -1 && out >= '0' && out <= '9') { start_of_digits_idx = idx; } else if (out == ',') { - // Don't allow group chars after the decimal point - if (decpt_idx != -1) + // Don't allow group chars after the decimal point or exponent + if (decpt_idx != -1 || exponent_idx != -1) return false; // check distance from the last separator or from the beginning of the digits @@ -3114,12 +3128,6 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti ++idx; continue; } else if (out == '.' || out == 'e' || out == 'E') { - // Fail if more than one decimal point - if (out == '.' && decpt_idx != -1) - return false; - if (decpt_idx == -1) - decpt_idx = idx; - // check distance from the last separator // ### FIXME: Some locales allow other groupings! See https://en.wikipedia.org/wiki/Thousands_separator if (last_separator_idx != -1 && idx - last_separator_idx != 4) @@ -3145,6 +3153,12 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti return false; } + if (number_options & QLocale::RejectTrailingZeroesAfterDot) { + // In decimal form, the last character can be a trailing zero if we've seen a decpt. + if (decpt_idx != -1 && exponent_idx == -1 && result->last() == '0') + return false; + } + result->append('\0'); return idx == l; } diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h index 657fce9fa1..bd89e48234 100644 --- a/src/corelib/tools/qlocale.h +++ b/src/corelib/tools/qlocale.h @@ -897,7 +897,9 @@ public: OmitGroupSeparator = 0x01, RejectGroupSeparator = 0x02, OmitLeadingZeroInExponent = 0x04, - RejectLeadingZeroInExponent = 0x08 + RejectLeadingZeroInExponent = 0x08, + IncludeTrailingZeroesAfterDot = 0x10, + RejectTrailingZeroesAfterDot = 0x20 }; Q_DECLARE_FLAGS(NumberOptions, NumberOption) diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc index f4b49095df..88b071e161 100644 --- a/src/corelib/tools/qlocale.qdoc +++ b/src/corelib/tools/qlocale.qdoc @@ -969,7 +969,8 @@ setNumberOptions(). \value DefaultNumberOptions This option represents the default behavior, with - group separators and with one leading zero in single digit exponents. + group separators, with one leading zero in single digit exponents, and + without trailing zeroes after the decimal dot. \value OmitGroupSeparator If this option is set, the number-to-string functions will not insert group separators in their return values. The default is to insert group separators. @@ -984,6 +985,14 @@ functions will fail if they encounter an exponent padded with zeroes when parsing a floating point number in scientific notation. The default is to accept such padding. + \value IncludeTrailingZeroesAfterDot If this option is set, the number-to-string + functions will pad numbers with zeroes to the requested precision in "g" + or "most concise" mode, even if the number of significant digits is lower + than the requested precision. The default is to omit trailing zeroes. + \value RejectTrailingZeroesAfterDot If this option is set, the string-to-number + functions will fail if they encounter trailing zeroes after the decimal + dot when parsing a number in scientific or decimal representation. The + default is to accept trailing zeroes. \sa setNumberOptions(), numberOptions() */ diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index c83c9d3333..74d8e5f381 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -193,7 +193,7 @@ public: enum Flags { NoFlags = 0, - Alternate = 0x01, + AddTrailingZeroes = 0x01, ZeroPadded = 0x02, LeftAdjusted = 0x04, BlankBeforePositive = 0x08, @@ -204,7 +204,7 @@ public: ShowBase = 0x80, UppercaseBase = 0x100, ZeroPadExponent = 0x200, - ForcePoint = Alternate + ForcePoint = 0x400 }; enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode }; diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index bf1bc3e650..942df9e0dd 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1758,17 +1758,11 @@ void QString::resize(int size, QChar fillChar) void QString::reallocData(uint alloc, bool grow) { - size_t blockSize; - if (grow) { - auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data)); - blockSize = r.size; - alloc = uint(r.elementCount); - } else { - blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data)); - } + auto allocOptions = d->detachFlags(); + if (grow) + allocOptions |= QArrayData::Grow; if (d->ref.isShared() || IS_RAW_DATA(d)) { - Data::AllocationOptions allocOptions(d->capacityReserved ? Data::CapacityReserved : 0); Data *x = Data::allocate(alloc, allocOptions); Q_CHECK_PTR(x); x->size = qMin(int(alloc) - 1, d->size); @@ -1778,11 +1772,9 @@ void QString::reallocData(uint alloc, bool grow) Data::deallocate(d); d = x; } else { - Data *p = static_cast<Data *>(::realloc(d, blockSize)); + Data *p = Data::reallocateUnaligned(d, alloc, allocOptions); Q_CHECK_PTR(p); d = p; - d->alloc = alloc; - d->offset = sizeof(QStringData); } } @@ -5916,7 +5908,10 @@ static uint parse_flag_characters(const char * &c) Q_DECL_NOTHROW uint flags = QLocaleData::ZeroPadExponent; while (true) { switch (*c) { - case '#': flags |= QLocaleData::Alternate; break; + case '#': + flags |= QLocaleData::ShowBase | QLocaleData::AddTrailingZeroes + | QLocaleData::ForcePoint; + break; case '0': flags |= QLocaleData::ZeroPadded; break; case '-': flags |= QLocaleData::LeftAdjusted; break; case ' ': flags |= QLocaleData::BlankBeforePositive; break; @@ -6174,7 +6169,7 @@ QString QString::vasprintf(const char *cformat, va_list ap) case 'p': { void *arg = va_arg(ap, void*); const quint64 i = reinterpret_cast<quintptr>(arg); - flags |= QLocaleData::Alternate; + flags |= QLocaleData::ShowBase; subst = QLocaleData::c()->unsLongLongToString(i, precision, 16, width, flags); ++c; break; @@ -7749,10 +7744,13 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha if (d.locale_occurrences > 0) { QLocale locale; - if (!(locale.numberOptions() & QLocale::OmitGroupSeparator)) + const QLocale::NumberOptions numberOptions = locale.numberOptions(); + if (!(numberOptions & QLocale::OmitGroupSeparator)) flags |= QLocaleData::ThousandsGroup; - if (!(locale.numberOptions() & QLocale::OmitLeadingZeroInExponent)) + if (!(numberOptions & QLocale::OmitLeadingZeroInExponent)) flags |= QLocaleData::ZeroPadExponent; + if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot) + flags |= QLocaleData::AddTrailingZeroes; locale_arg = locale.d->m_data->doubleToString(a, prec, form, fieldWidth, flags); } diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index db118edf04..094f44b2ab 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -137,8 +137,8 @@ static qreal qt_effective_device_pixel_ratio(QWindow *window = 0) return qApp->devicePixelRatio(); // Don't know which window to target. } -QIconPrivate::QIconPrivate() - : engine(0), ref(1), +QIconPrivate::QIconPrivate(QIconEngine *e) + : engine(e), ref(1), serialNum(serialNumCounter.fetchAndAddRelaxed(1)), detach_no(0), is_mask(false) @@ -673,9 +673,8 @@ QIcon::QIcon(const QString &fileName) ownership of the engine. */ QIcon::QIcon(QIconEngine *engine) - :d(new QIconPrivate) + :d(new QIconPrivate(engine)) { - d->engine = engine; } /*! @@ -950,8 +949,7 @@ void QIcon::detach() d = 0; return; } else if (d->ref.load() != 1) { - QIconPrivate *x = new QIconPrivate; - x->engine = d->engine->clone(); + QIconPrivate *x = new QIconPrivate(d->engine->clone()); if (!d->ref.deref()) delete d; d = x; @@ -974,10 +972,8 @@ void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state) if (pixmap.isNull()) return; detach(); - if (!d) { - d = new QIconPrivate; - d->engine = new QPixmapIconEngine; - } + if (!d) + d = new QIconPrivate(new QPixmapIconEngine); d->engine->addPixmap(pixmap, mode, state); } @@ -1037,8 +1033,7 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State if (!engine) engine = iconEngineFromSuffix(fileName, QMimeDatabase().mimeTypeForFile(info).preferredSuffix()); #endif // !QT_NO_MIMETYPE - d = new QIconPrivate; - d->engine = engine ? engine : new QPixmapIconEngine; + d = new QIconPrivate(engine ? engine : new QPixmapIconEngine); } d->engine->addFile(fileName, size, mode, state); @@ -1240,12 +1235,10 @@ bool QIcon::hasThemeIcon(const QString &name) */ void QIcon::setIsMask(bool isMask) { - if (!d) { - d = new QIconPrivate; - d->engine = new QPixmapIconEngine; - } else { + if (!d) + d = new QIconPrivate(new QPixmapIconEngine); + else detach(); - } d->is_mask = isMask; } @@ -1326,22 +1319,17 @@ QDataStream &operator>>(QDataStream &s, QIcon &icon) QString key; s >> key; if (key == QLatin1String("QPixmapIconEngine")) { - icon.d = new QIconPrivate; - QIconEngine *engine = new QPixmapIconEngine; - icon.d->engine = engine; - engine->read(s); + icon.d = new QIconPrivate(new QPixmapIconEngine); + icon.d->engine->read(s); } else if (key == QLatin1String("QIconLoaderEngine")) { - icon.d = new QIconPrivate; - QIconEngine *engine = new QIconLoaderEngine(); - icon.d->engine = engine; - engine->read(s); + icon.d = new QIconPrivate(new QIconLoaderEngine()); + icon.d->engine->read(s); } else { const int index = loader()->indexOf(key); if (index != -1) { if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(loader()->instance(index))) { if (QIconEngine *engine= factory->create()) { - icon.d = new QIconPrivate; - icon.d->engine = engine; + icon.d = new QIconPrivate(engine); engine->read(s); } // factory } // instance diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h index a978a72192..aa358e88af 100644 --- a/src/gui/image/qicon_p.h +++ b/src/gui/image/qicon_p.h @@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE class QIconPrivate { public: - QIconPrivate(); + explicit QIconPrivate(QIconEngine *e); ~QIconPrivate() { delete engine; diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp index 1a8fc599ce..4f4f543ba8 100644 --- a/src/gui/opengl/qopengl.cpp +++ b/src/gui/opengl/qopengl.cpp @@ -42,6 +42,7 @@ #include "qopenglcontext.h" #include "qopenglfunctions.h" +#include "qoperatingsystemversion.h" #include "qoffscreensurface.h" #include <QtCore/QDebug> @@ -221,29 +222,25 @@ struct OsTypeTerm static QString hostOsRelease() { QString ver; #ifdef Q_OS_WIN - switch (QSysInfo::windowsVersion()) { - case QSysInfo::WV_XP: - case QSysInfo::WV_2003: - ver = QStringLiteral("xp"); - break; - case QSysInfo::WV_VISTA: - ver = QStringLiteral("vista"); - break; - case QSysInfo::WV_WINDOWS7: + const auto osver = QOperatingSystemVersion::current(); +#define Q_WINVER(major, minor) (major << 8 | minor) + switch (Q_WINVER(osver.majorVersion(), osver.minorVersion())) { + case Q_WINVER(6, 1): ver = QStringLiteral("7"); break; - case QSysInfo::WV_WINDOWS8: + case Q_WINVER(6, 2): ver = QStringLiteral("8"); break; - case QSysInfo::WV_WINDOWS8_1: + case Q_WINVER(6, 3): ver = QStringLiteral("8.1"); break; - case QSysInfo::WV_WINDOWS10: + case Q_WINVER(10, 0): ver = QStringLiteral("10"); break; default: break; } +#undef Q_WINVER #endif return ver; } diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index 61343e5f5a..6f5aff14aa 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -162,6 +162,79 @@ QT_BEGIN_NAMESPACE based on the core feature (requires OpenGL >= 4.3). */ + +// For GLES 3.1/3.2 +#ifndef GL_GEOMETRY_SHADER +#define GL_GEOMETRY_SHADER 0x8DD9 +#endif +#ifndef GL_TESS_CONTROL_SHADER +#define GL_TESS_CONTROL_SHADER 0x8E88 +#endif +#ifndef GL_TESS_EVALUATION_SHADER +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#endif +#ifndef GL_COMPUTE_SHADER +#define GL_COMPUTE_SHADER 0x91B9 +#endif +#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#endif +#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#endif +#ifndef GL_PATCH_VERTICES +#define GL_PATCH_VERTICES 0x8E72 +#endif +#ifndef GL_PATCH_DEFAULT_OUTER_LEVEL +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#endif +#ifndef GL_PATCH_DEFAULT_INNER_LEVEL +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#endif + +static inline bool isFormatGLES(const QSurfaceFormat &f) +{ + return (f.renderableType() == QSurfaceFormat::OpenGLES); +} + +static inline bool supportsGeometry(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair<int, int>(3, 2)); + else + return false; +#else + Q_UNUSED(f); + return false; +#endif +} + +static inline bool supportsCompute(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair<int, int>(4, 3)); + else + return (f.version() >= qMakePair<int, int>(3, 1)); +#else + return (f.version() >= qMakePair<int, int>(3, 1)); +#endif +} + +static inline bool supportsTessellation(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair<int, int>(4, 0)); + else + return false; +#else + Q_UNUSED(f); + return false; +#endif +} + class QOpenGLShaderPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QOpenGLShader) @@ -171,22 +244,16 @@ public: , shaderType(type) , compiled(false) , glfuncs(new QOpenGLFunctions(ctx)) -#ifndef QT_OPENGL_ES_2 , supportsGeometryShaders(false) , supportsTessellationShaders(false) -#endif + , supportsComputeShaders(false) { -#ifndef QT_OPENGL_ES_2 - if (!ctx->isOpenGLES()) { - QSurfaceFormat f = ctx->format(); - - // Geometry shaders require OpenGL >= 3.2 - if (shaderType & QOpenGLShader::Geometry) - supportsGeometryShaders = (f.version() >= qMakePair<int, int>(3, 2)); - else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) - supportsTessellationShaders = (f.version() >= qMakePair<int, int>(4, 0)); - } -#endif + if (shaderType & QOpenGLShader::Geometry) + supportsGeometryShaders = supportsGeometry(ctx->format()); + else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) + supportsTessellationShaders = supportsTessellation(ctx->format()); + else if (shaderType & QOpenGLShader::Compute) + supportsComputeShaders = supportsCompute(ctx->format()); } ~QOpenGLShaderPrivate(); @@ -197,13 +264,13 @@ public: QOpenGLFunctions *glfuncs; -#ifndef QT_OPENGL_ES_2 // Support for geometry shaders bool supportsGeometryShaders; - // Support for tessellation shaders bool supportsTessellationShaders; -#endif + // Support for compute shaders + bool supportsComputeShaders; + bool create(); bool compile(QOpenGLShader *q); @@ -232,21 +299,15 @@ bool QOpenGLShaderPrivate::create() GLuint shader; if (shaderType == QOpenGLShader::Vertex) { shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); -#if defined(QT_OPENGL_3_2) } else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) { shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER); -#endif -#if defined(QT_OPENGL_4) } else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) { shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER); } else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) { shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER); -#endif -#if defined(QT_OPENGL_4_3) - } else if (shaderType == QOpenGLShader::Compute) { + } else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) { shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER); -#endif - } else { + } else if (shaderType == QOpenGLShader::Fragment) { shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); } if (!shader) { @@ -3219,10 +3280,8 @@ void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4 int QOpenGLShaderProgram::maxGeometryOutputVertices() const { GLint n = 0; -#if defined(QT_OPENGL_3_2) Q_D(const QOpenGLShaderProgram); d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n); -#endif return n; } @@ -3246,7 +3305,7 @@ int QOpenGLShaderProgram::maxGeometryOutputVertices() const */ void QOpenGLShaderProgram::setPatchVertexCount(int count) { -#if defined(QT_OPENGL_4) +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glPatchParameteri(GL_PATCH_VERTICES, count); @@ -3265,13 +3324,15 @@ void QOpenGLShaderProgram::setPatchVertexCount(int count) */ int QOpenGLShaderProgram::patchVertexCount() const { +#ifndef QT_OPENGL_ES_2 int patchVertices = 0; -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices); -#endif return patchVertices; +#else + return 0; +#endif } /*! @@ -3293,21 +3354,21 @@ int QOpenGLShaderProgram::patchVertexCount() const */ void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float> &levels) { -#if defined(QT_OPENGL_4) - QVector<float> tessLevels = levels; - - // Ensure we have the required 4 outer tessellation levels - // Use default of 1 for missing entries (same as spec) - const int argCount = 4; - if (tessLevels.size() < argCount) { - tessLevels.reserve(argCount); - for (int i = tessLevels.size(); i < argCount; ++i) - tessLevels.append(1.0f); - } - +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) + if (d->tessellationFuncs) { + QVector<float> tessLevels = levels; + + // Ensure we have the required 4 outer tessellation levels + // Use default of 1 for missing entries (same as spec) + const int argCount = 4; + if (tessLevels.size() < argCount) { + tessLevels.reserve(argCount); + for (int i = tessLevels.size(); i < argCount; ++i) + tessLevels.append(1.0f); + } d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); + } #else Q_UNUSED(levels); #endif @@ -3330,13 +3391,15 @@ void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float */ QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const { +#ifndef QT_OPENGL_ES_2 QVector<float> tessLevels(4, 1.0f); -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); -#endif return tessLevels; +#else + return QVector<float>(); +#endif } /*! @@ -3358,21 +3421,21 @@ QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const */ void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float> &levels) { -#if defined(QT_OPENGL_4) - QVector<float> tessLevels = levels; - - // Ensure we have the required 2 inner tessellation levels - // Use default of 1 for missing entries (same as spec) - const int argCount = 2; - if (tessLevels.size() < argCount) { - tessLevels.reserve(argCount); - for (int i = tessLevels.size(); i < argCount; ++i) - tessLevels.append(1.0f); - } - +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) + if (d->tessellationFuncs) { + QVector<float> tessLevels = levels; + + // Ensure we have the required 2 inner tessellation levels + // Use default of 1 for missing entries (same as spec) + const int argCount = 2; + if (tessLevels.size() < argCount) { + tessLevels.reserve(argCount); + for (int i = tessLevels.size(); i < argCount; ++i) + tessLevels.append(1.0f); + } d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); + } #else Q_UNUSED(levels); #endif @@ -3395,13 +3458,15 @@ void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float */ QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const { +#ifndef QT_OPENGL_ES_2 QVector<float> tessLevels(2, 1.0f); -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); -#endif return tessLevels; +#else + return QVector<float>(); +#endif } @@ -3414,16 +3479,11 @@ QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const */ bool QOpenGLShaderProgram::hasOpenGLShaderPrograms(QOpenGLContext *context) { -#if !defined(QT_OPENGL_ES_2) if (!context) context = QOpenGLContext::currentContext(); if (!context) return false; return QOpenGLFunctions(context).hasOpenGLFeature(QOpenGLFunctions::Shaders); -#else - Q_UNUSED(context); - return true; -#endif } /*! @@ -3454,33 +3514,12 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) if ((type & ~(Geometry | Vertex | Fragment | TessellationControl | TessellationEvaluation | Compute)) || type == 0) return false; - QSurfaceFormat format = context->format(); - if (type == Geometry) { -#ifndef QT_OPENGL_ES_2 - // Geometry shaders require OpenGL 3.2 or newer - QSurfaceFormat format = context->format(); - return (!context->isOpenGLES()) - && (format.version() >= qMakePair<int, int>(3, 2)); -#else - // No geometry shader support in OpenGL ES2 - return false; -#endif - } else if (type == TessellationControl || type == TessellationEvaluation) { -#if !defined(QT_OPENGL_ES_2) - return (!context->isOpenGLES()) - && (format.version() >= qMakePair<int, int>(4, 0)); -#else - // No tessellation shader support in OpenGL ES2 - return false; -#endif - } else if (type == Compute) { -#if defined(QT_OPENGL_4_3) - return (format.version() >= qMakePair<int, int>(4, 3)); -#else - // No compute shader support without OpenGL 4.3 or newer - return false; -#endif - } + if (type & QOpenGLShader::Geometry) + return supportsGeometry(context->format()); + else if (type & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) + return supportsTessellation(context->format()); + else if (type & QOpenGLShader::Compute) + return supportsCompute(context->format()); // Unconditional support of vertex and fragment shaders implicitly assumes // a minimum OpenGL version of 2.0 diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm index 6af12c19d8..a29d60ca6e 100644 --- a/src/gui/painting/qcoregraphics.mm +++ b/src/gui/painting/qcoregraphics.mm @@ -39,6 +39,7 @@ #include <QtGui/private/qpaintengine_p.h> #include <QtCore/qdebug.h> #include <QtCore/qcoreapplication.h> +#include <QtCore/qoperatingsystemversion.h> QT_BEGIN_NAMESPACE @@ -119,7 +120,7 @@ QT_END_NAMESPACE + (NSGraphicsContext *)qt_graphicsContextWithCGContext:(CGContextRef)graphicsPort flipped:(BOOL)initialFlippedState { #if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_NA) - if (QT_PREPEND_NAMESPACE(QSysInfo::MacintoshVersion) >= QT_PREPEND_NAMESPACE(QSysInfo::MV_10_10)) + if (QT_PREPEND_NAMESPACE(QOperatingSystemVersion::current()) >= QT_PREPEND_NAMESPACE(QOperatingSystemVersion::OSXYosemite)) return [self graphicsContextWithCGContext:graphicsPort flipped:initialFlippedState]; #endif return [self graphicsContextWithGraphicsPort:graphicsPort flipped:initialFlippedState]; diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp index 085c073bb1..c9747877f7 100644 --- a/src/gui/util/qdesktopservices.cpp +++ b/src/gui/util/qdesktopservices.cpp @@ -198,8 +198,15 @@ bool QDesktopServices::openUrl(const QUrl &url) return false; QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); - if (!platformIntegration) + if (Q_UNLIKELY(!platformIntegration)) { + QCoreApplication *application = QCoreApplication::instance(); + if (Q_UNLIKELY(!application)) + qWarning("QDesktopServices::openUrl: Please instantiate the QGuiApplication object " + "first"); + else if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(application))) + qWarning("QDesktopServices::openUrl: Application is not a GUI application"); return false; + } QPlatformServices *platformServices = platformIntegration->services(); if (!platformServices) { diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index 24ada3a81f..612abb9044 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -299,6 +299,11 @@ void QHttpNetworkReply::setSpdyWasUsed(bool spdy) d_func()->spdyUsed = spdy; } +qint64 QHttpNetworkReply::removedContentLength() const +{ + return d_func()->removedContentLength; +} + bool QHttpNetworkReply::isRedirecting() const { return d_func()->isRedirecting(); @@ -326,6 +331,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) currentlyReceivedDataInWindow(0), currentlyUploadedDataInWindow(0), totallyUploadedData(0), + removedContentLength(-1), connection(0), autoDecompress(false), responseData(), requestIsPrepared(false) ,pipeliningUsed(false), spdyUsed(false), downstreamLimited(false) @@ -398,12 +404,12 @@ void QHttpNetworkReplyPrivate::removeAutoDecompressHeader() end = fields.end(); while (it != end) { if (qstricmp(name.constData(), it->first.constData()) == 0) { + removedContentLength = strtoull(it->second.constData(), nullptr, 0); fields.erase(it); break; } ++it; } - } bool QHttpNetworkReplyPrivate::findChallenge(bool forProxy, QByteArray &challenge) const diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index f3b007f594..faab03f056 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -139,6 +139,7 @@ public: bool isPipeliningUsed() const; bool isSpdyUsed() const; void setSpdyWasUsed(bool spdy); + qint64 removedContentLength() const; bool isRedirecting() const; @@ -255,6 +256,7 @@ public: qint32 currentlyReceivedDataInWindow; // only for SPDY qint32 currentlyUploadedDataInWindow; // only for SPDY qint64 totallyUploadedData; // only for SPDY + qint64 removedContentLength; QPointer<QHttpNetworkConnection> connection; QPointer<QHttpNetworkConnectionChannel> connectionChannel; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 1dca7f02fb..e71911cec2 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -234,6 +234,7 @@ QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) : , isPipeliningUsed(false) , isSpdyUsed(false) , incomingContentLength(-1) + , removedContentLength(-1) , incomingErrorCode(QNetworkReply::NoError) , downloadBuffer() , httpConnection(0) @@ -623,6 +624,7 @@ void QHttpThreadDelegate::headerChangedSlot() incomingReasonPhrase = httpReply->reasonPhrase(); isPipeliningUsed = httpReply->isPipeliningUsed(); incomingContentLength = httpReply->contentLength(); + removedContentLength = httpReply->removedContentLength(); isSpdyUsed = httpReply->isSpdyUsed(); emit downloadMetaData(incomingHeaders, @@ -631,6 +633,7 @@ void QHttpThreadDelegate::headerChangedSlot() isPipeliningUsed, downloadBuffer, incomingContentLength, + removedContentLength, isSpdyUsed); } diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 64c58cf648..6d1ea11f29 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -112,6 +112,7 @@ public: bool isPipeliningUsed; bool isSpdyUsed; qint64 incomingContentLength; + qint64 removedContentLength; QNetworkReply::NetworkError incomingErrorCode; QString incomingErrorDetail; #ifndef QT_NO_BEARERMANAGEMENT @@ -141,7 +142,7 @@ signals: void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *); #endif void downloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &, bool, - QSharedPointer<char>, qint64, bool); + QSharedPointer<char>, qint64, qint64, bool); void downloadProgress(qint64, qint64); void downloadData(const QByteArray &); void error(QNetworkReply::NetworkError, const QString &); diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h index 7f39c942a3..4b5422ce29 100644 --- a/src/network/access/qnetworkaccessbackend_p.h +++ b/src/network/access/qnetworkaccessbackend_p.h @@ -63,7 +63,6 @@ class QNetworkProxyQuery; class QNetworkRequest; class QStringList; class QUrl; -class QUrlInfo; class QSslConfiguration; class QNetworkAccessManagerPrivate; diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index b5e44fa29a..f70f11d384 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -805,10 +805,11 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq Qt::QueuedConnection); QObject::connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >, int, QString, bool, - QSharedPointer<char>, qint64, bool)), + QSharedPointer<char>, qint64, qint64, + bool)), q, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >, int, QString, bool, - QSharedPointer<char>, qint64, bool)), + QSharedPointer<char>, qint64, qint64, bool)), Qt::QueuedConnection); QObject::connect(delegate, SIGNAL(downloadProgress(qint64,qint64)), q, SLOT(replyDownloadProgressSlot(qint64,qint64)), @@ -913,6 +914,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq delegate->isPipeliningUsed, QSharedPointer<char>(), delegate->incomingContentLength, + delegate->removedContentLength, delegate->isSpdyUsed); replyDownloadData(delegate->synchronousDownloadData); httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail); @@ -924,6 +926,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq delegate->isPipeliningUsed, QSharedPointer<char>(), delegate->incomingContentLength, + delegate->removedContentLength, delegate->isSpdyUsed); replyDownloadData(delegate->synchronousDownloadData); } @@ -1151,7 +1154,9 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode) void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &hm, int sc, const QString &rp, bool pu, QSharedPointer<char> db, - qint64 contentLength, bool spdyWasUsed) + qint64 contentLength, + qint64 removedContentLength, + bool spdyWasUsed) { Q_Q(QNetworkReplyHttpImpl); Q_UNUSED(contentLength); @@ -1197,6 +1202,8 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode); q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase); + if (removedContentLength != -1) + q->setAttribute(QNetworkRequest::OriginalContentLengthAttribute, removedContentLength); // is it a redirection? if (!isHttpRedirectResponse()) diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 868fa617b6..255c23006e 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -114,7 +114,7 @@ public: Q_PRIVATE_SLOT(d_func(), void replyFinished()) Q_PRIVATE_SLOT(d_func(), void replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >, int, QString, bool, QSharedPointer<char>, - qint64, bool)) + qint64, qint64, bool)) Q_PRIVATE_SLOT(d_func(), void replyDownloadProgressSlot(qint64,qint64)) Q_PRIVATE_SLOT(d_func(), void httpAuthenticationRequired(const QHttpNetworkRequest &, QAuthenticator *)) Q_PRIVATE_SLOT(d_func(), void httpError(QNetworkReply::NetworkError, const QString &)) @@ -280,7 +280,7 @@ public: void replyDownloadData(QByteArray); void replyFinished(); void replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &, - bool, QSharedPointer<char>, qint64, bool); + bool, QSharedPointer<char>, qint64, qint64, bool); void replyDownloadProgressSlot(qint64,qint64); void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth); void httpError(QNetworkReply::NetworkError error, const QString &errorString); diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 29362b81e2..bc2507ca51 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -282,6 +282,13 @@ QT_BEGIN_NAMESPACE that is redirecting from "https" to "http" protocol, are not allowed. (This value was introduced in 5.6.) + \value OriginalContentLengthAttribute + Replies only, type QMetaType::Int + Holds the original content-length attribute before being invalidated and + removed from the header when the data is compressed and the request was + marked to be decompressed automatically. + (This value was introduced in 5.9.) + \value User Special type. Additional information can be passed in QVariants with types ranging from User to UserMax. The default diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index ad8f5bddd9..9a3a7f0fb5 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -91,6 +91,7 @@ public: FollowRedirectsAttribute, HTTP2AllowedAttribute, HTTP2WasUsedAttribute, + OriginalContentLengthAttribute, User = 1000, UserMax = 32767 diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 8f37e28669..7ef387beb4 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -57,8 +57,7 @@ win32: { mac { LIBS_PRIVATE += -framework CoreFoundation - !uikit: LIBS_PRIVATE += -framework CoreServices - !if(watchos:CONFIG(device, simulator|device)): LIBS_PRIVATE += -framework SystemConfiguration + !uikit: LIBS_PRIVATE += -framework CoreServices -framework SystemConfiguration } osx:SOURCES += kernel/qnetworkproxy_mac.cpp diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp index f5dc9fcdcd..ca65f8a015 100644 --- a/src/network/ssl/qsslsocket_winrt.cpp +++ b/src/network/ssl/qsslsocket_winrt.cpp @@ -181,13 +181,7 @@ long QSslSocketPrivate::sslLibraryVersionNumber() QString QSslSocketPrivate::sslLibraryVersionString() { - switch (QSysInfo::windowsVersion()) { - case QSysInfo::WV_WINDOWS8_1: - return QStringLiteral("Windows Runtime 8.1 SSL library"); - default: - break; - } - return QStringLiteral("Windows Runtime SSL library"); + return QStringLiteral("Windows Runtime, ") + QSysInfo::prettyProductName(); } long QSslSocketPrivate::sslLibraryBuildVersionNumber() diff --git a/src/platformsupport/fontdatabases/fontdatabases.pri b/src/platformsupport/fontdatabases/fontdatabases.pri index f8e51f2a6d..1ea7f42204 100644 --- a/src/platformsupport/fontdatabases/fontdatabases.pri +++ b/src/platformsupport/fontdatabases/fontdatabases.pri @@ -1,4 +1,4 @@ -darwin:!if(watchos:CONFIG(simulator, simulator|device)) { +darwin { include($$PWD/mac/coretext.pri) } else { !win32|qtConfig(freetype) { diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri index 4d19a59226..e1132cfcbe 100644 --- a/src/platformsupport/fontdatabases/mac/coretext.pri +++ b/src/platformsupport/fontdatabases/mac/coretext.pri @@ -14,3 +14,13 @@ else: \ # On Mac OS they are part of the ApplicationServices umbrella framework, # even in 10.8 where they were also made available stand-alone. LIBS_PRIVATE += -framework ApplicationServices + +# CoreText is documented to be available on watchOS, but the headers aren't present +# in the watchOS Simulator SDK like they are supposed to be. Work around the problem +# by adding the device SDK's headers to the search path as a fallback. +# rdar://25314492, rdar://27844864 +watchos:CONFIG(simulator, simulator|device) { + QMAKE_CXXFLAGS += \ + -F$$xcodeSDKInfo(Path, $${simulator.sdk})/System/Library/Frameworks \ + -F$$xcodeSDKInfo(Path, $${device.sdk})/System/Library/Frameworks +} diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index 7d11023b78..de4fa95530 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -132,7 +132,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o) QPixmap pm = dragPixmap(m_drag, hotSpot); QSize pmDeviceIndependentSize = pm.size() / pm.devicePixelRatio(); NSImage *nsimage = qt_mac_create_nsimage(pm); - [nsimage setSize:pmDeviceIndependentSize.toCGSize()]; + [nsimage setSize:NSSizeFromCGSize(pmDeviceIndependentSize.toCGSize())]; QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacInternalPasteboardMime::MIME_DND); m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy")); diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 0375dd85f2..c0055852c2 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -62,6 +62,7 @@ #include <stdlib.h> #include <qabstracteventdispatcher.h> #include <qsysinfo.h> +#include <qoperatingsystemversion.h> #include <qglobal.h> #include <QDir> @@ -163,7 +164,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate); [mSavePanel setDelegate:self]; #if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_11) - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_11) + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXElCapitan) mOpenPanel.accessoryViewDisclosed = YES; #endif diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index b2fd0580bc..87a0991098 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -514,7 +514,7 @@ QRect QCocoaWindow::geometry() const NSRect screenRect = [[m_contentView window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)]; NSPoint screenPoint = screenRect.origin; QPoint position = qt_mac_flipPoint(screenPoint).toPoint(); - QSize size = QRectF::fromCGRect([m_contentView bounds]).toRect().size(); + QSize size = QRectF::fromCGRect(NSRectToCGRect([m_contentView bounds])).toRect().size(); return QRect(position, size); } @@ -1117,7 +1117,7 @@ void QCocoaWindow::propagateSizeHints() QSize sizeIncrement = windowSizeIncrement(); if (sizeIncrement.isEmpty()) sizeIncrement = QSize(1, 1); - [m_nsWindow setResizeIncrements:sizeIncrement.toCGSize()]; + [m_nsWindow setResizeIncrements:NSSizeFromCGSize(sizeIncrement.toCGSize())]; QRect rect = geometry(); QSize baseSize = windowBaseSize(); diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 8d3b970158..ee0bf75606 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -340,10 +340,10 @@ static bool _q_dontOverrideCtrlLMB = false; geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height); } else if (m_platformWindow->m_contentViewIsToBeEmbedded) { // embedded child window, use the frame rect ### merge with case below - geometry = QRectF::fromCGRect([self bounds]).toRect(); + geometry = QRectF::fromCGRect(NSRectToCGRect([self bounds])).toRect(); } else { // child window, use the frame rect - geometry = QRectF::fromCGRect([self frame]).toRect(); + geometry = QRectF::fromCGRect(NSRectToCGRect([self frame])).toRect(); } if (m_platformWindow->m_nsWindow && geometry == m_platformWindow->geometry()) @@ -557,7 +557,7 @@ static bool _q_dontOverrideCtrlLMB = false; - (void) drawRect:(NSRect)dirtyRect { - qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_window << QRectF::fromCGRect(dirtyRect); + qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_window << QRectF::fromCGRect(NSRectToCGRect(dirtyRect)); #ifndef QT_NO_OPENGL if (m_glContext && m_shouldSetGLContextinDrawRect) { @@ -1347,7 +1347,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (bool)handleGestureAsBeginEnd:(NSEvent *)event { - if (QSysInfo::QSysInfo::MacintoshVersion < QSysInfo::MV_10_11) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXElCapitan) return false; if ([event phase] == NSEventPhaseBegan) { diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 94dd643116..9799e29cf2 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -60,6 +60,7 @@ #include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> #include <QtPlatformSupport/private/qmacmime_p.h> #include <QDir> +#include <QOperatingSystemVersion> #import <AudioToolbox/AudioServices.h> @@ -117,7 +118,7 @@ QIOSIntegration::QIOSIntegration() m_touchDevice = new QTouchDevice; m_touchDevice->setType(QTouchDevice::TouchScreen); QTouchDevice::Capabilities touchCapabilities = QTouchDevice::Position | QTouchDevice::NormalizedPosition; - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_9_0) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)) { if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) touchCapabilities |= QTouchDevice::Pressure; } diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm index 50d5442f17..4f0c667861 100644 --- a/src/plugins/platforms/ios/qiosmessagedialog.mm +++ b/src/plugins/platforms/ios/qiosmessagedialog.mm @@ -39,6 +39,7 @@ #import <UIKit/UIKit.h> +#include <QtCore/qoperatingsystemversion.h> #include <QtGui/qwindow.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformtheme.h> @@ -109,7 +110,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win if (m_alertController // Ensure that the dialog is not showing already || !options() // Some message dialogs don't have options (QErrorMessage) || windowModality == Qt::NonModal // We can only do modal dialogs - || QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_8_0) // API limitation + || QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) // API limitation return false; m_alertController = [[UIAlertController diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index 013061a6d2..86bce0d70b 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -45,6 +45,7 @@ #include "qiosapplicationdelegate.h" #include "qiosviewcontroller.h" #include "quiview.h" +#include <QtCore/qoperatingsystemversion.h> #include <QtGui/private/qwindow_p.h> #include <private/qcoregraphics_p.h> @@ -274,7 +275,7 @@ void QIOSScreen::updateProperties() if (m_uiScreen == [UIScreen mainScreen]) { Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation)); - if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_8_0) { + if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { // On iOS < 8.0 the UIScreen geometry is always in portait, and the system applies // the screen rotation to the root view-controller's view instead of directly to the // screen, like iOS 8 and above does. @@ -302,7 +303,7 @@ void QIOSScreen::updateProperties() if (m_geometry != previousGeometry) { QRectF physicalGeometry; - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { // We can't use the primaryOrientation of screen(), as we haven't reported the new geometry yet Qt::ScreenOrientation primaryOrientation = m_geometry.width() >= m_geometry.height() ? Qt::LandscapeOrientation : Qt::PortraitOrientation; @@ -407,7 +408,7 @@ Qt::ScreenOrientation QIOSScreen::nativeOrientation() const { CGRect nativeBounds = #if !defined(Q_OS_TVOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) - QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0 ? m_uiScreen.nativeBounds : + QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8) ? m_uiScreen.nativeBounds : #endif m_uiScreen.bounds; diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm index 9d73a296fa..462da0a978 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.mm +++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm @@ -219,7 +219,7 @@ static void executeBlockWithoutAnimation(Block block) borderLayer.borderColor = [[UIColor lightGrayColor] CGColor]; [self addSublayer:borderLayer]; - if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) { + if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 7)) { // [UIView snapshotViewAfterScreenUpdates:] is available since iOS 7.0. // Just silently ignore showing the loupe for older versions. self.hidden = YES; @@ -267,7 +267,7 @@ static void executeBlockWithoutAnimation(Block block) - (void)display { - if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 7)) return; // Take a snapshow of the target view, magnify the area around the focal diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 5c493617b1..25bfa2ad90 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -48,6 +48,7 @@ #include "qiosmenu.h" #endif +#include <QtCore/qoperatingsystemversion.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qwindow_p.h> #include <qpa/qwindowsysteminterface_p.h> @@ -298,7 +299,7 @@ QTouchDevice *touchDevice = QIOSIntegration::instance()->touchDevice(); QTouchDevice::Capabilities touchCapabilities = touchDevice->capabilities(); - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_9_0) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)) { if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) touchCapabilities |= QTouchDevice::Pressure; else diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index ff115a2249..5d4afe8fb2 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -1053,11 +1053,24 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BS return S_FALSE; } -HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR) +HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR value) { QAccessibleInterface *accessible = accessibleInterface(); accessibleDebugClientCalls(accessible); - return DISP_E_MEMBERNOTFOUND; + + if (!accessible || !accessible->isValid()) { + return E_FAIL; + } + + QString qstrValue = QString::fromWCharArray(value); + + if (accessible->valueInterface()) { + accessible->valueInterface()->setCurrentValue(qstrValue); + } else { + accessible->setText(QAccessible::Value, qstrValue); + } + + return S_OK; } // moz: [important] diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index d4cdf3ef3c..10d38f2a0c 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -68,6 +68,7 @@ #include <QtCore/QHash> #include <QtCore/QStringList> #include <QtCore/QDebug> +#include <QtCore/QOperatingSystemVersion> #include <QtCore/QSysInfo> #include <QtCore/QScopedArrayPointer> #include <QtCore/private/qsystemlibrary_p.h> @@ -186,7 +187,7 @@ QWindowsShcoreDLL::QWindowsShcoreDLL() void QWindowsShcoreDLL::init() { - if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) return; QSystemLibrary library(QStringLiteral("SHCore")); getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness"); diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 26a5131927..9519b509bc 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -190,6 +190,20 @@ static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState) return modifiers; } +static inline Qt::MouseButtons toQtMouseButtons(DWORD keyState) +{ + Qt::MouseButtons buttons = Qt::NoButton; + + if (keyState & MK_LBUTTON) + buttons |= Qt::LeftButton; + if (keyState & MK_RBUTTON) + buttons |= Qt::RightButton; + if (keyState & MK_MBUTTON) + buttons |= Qt::MidButton; + + return buttons; +} + /*! \class QWindowsOleDropSource \brief Implementation of IDropSource @@ -405,16 +419,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) break; } - // grfKeyState is broken on CE & some Windows XP versions, - // therefore we need to check the state manually - if ((GetAsyncKeyState(VK_LBUTTON) == 0) - && (GetAsyncKeyState(VK_MBUTTON) == 0) - && (GetAsyncKeyState(VK_RBUTTON) == 0)) { - hr = ResultFromScode(DRAGDROP_S_DROP); - break; - } - - const Qt::MouseButtons buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); + const Qt::MouseButtons buttons = toQtMouseButtons(grfKeyState); if (m_currentButtons == Qt::NoButton) { m_currentButtons = buttons; } else { @@ -538,7 +543,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState); - QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); + QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState); const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index d577d46b96..d1d7be123d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -130,7 +130,7 @@ typedef struct qt_xcb_ge_event_t { static inline bool isXIEvent(xcb_generic_event_t *event, int opCode) { - qt_xcb_ge_event_t *e = (qt_xcb_ge_event_t *)event; + qt_xcb_ge_event_t *e = reinterpret_cast<qt_xcb_ge_event_t *>(event); return e->extension == opCode; } @@ -249,7 +249,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) // Find a fake screen const auto scrs = virtualDesktop->screens(); for (QPlatformScreen *scr : scrs) { - QXcbScreen *xcbScreen = (QXcbScreen *)scr; + QXcbScreen *xcbScreen = static_cast<QXcbScreen *>(scr); if (xcbScreen->output() == XCB_NONE) { screen = xcbScreen; break; @@ -375,7 +375,7 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen) // When primary screen is removed, set the new primary screen // which belongs to the primary virtual desktop. if (screen->isPrimary()) { - QXcbScreen *newPrimary = (QXcbScreen *)virtualDesktop->screens().at(0); + QXcbScreen *newPrimary = static_cast<QXcbScreen *>(virtualDesktop->screens().at(0)); newPrimary->setPrimary(true); const int idx = m_screens.indexOf(newPrimary); if (idx > 0) @@ -709,7 +709,7 @@ QXcbConnection::~QXcbConnection() delete m_glIntegration; #ifdef XCB_USE_XLIB - XCloseDisplay((Display *)m_xlib_display); + XCloseDisplay(static_cast<Display *>(m_xlib_display)); #else xcb_disconnect(xcb_connection()); #endif @@ -752,7 +752,7 @@ QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \ { \ - event_t *e = (event_t *)event; \ + event_t *e = reinterpret_cast<event_t *>(event); \ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \ handled = eventListener->handleGenericEvent(event, &result); \ if (!handled) \ @@ -763,7 +763,7 @@ break; #define HANDLE_KEYBOARD_EVENT(event_t, handler) \ { \ - event_t *e = (event_t *)event; \ + event_t *e = reinterpret_cast<event_t *>(event); \ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \ handled = eventListener->handleGenericEvent(event, &result); \ if (!handled) \ @@ -1182,11 +1182,11 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state); HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); case XCB_MAPPING_NOTIFY: - m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event); + m_keyboard->handleMappingNotifyEvent(reinterpret_cast<xcb_mapping_notify_event_t *>(event)); break; case XCB_SELECTION_REQUEST: { - xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event; + xcb_selection_request_event_t *sr = reinterpret_cast<xcb_selection_request_event_t *>(event); #ifndef QT_NO_DRAGANDDROP if (sr->selection == atom(QXcbAtom::XdndSelection)) m_drag->handleSelectionRequest(sr); @@ -1200,19 +1200,19 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) break; } case XCB_SELECTION_CLEAR: - setTime(((xcb_selection_clear_event_t *)event)->time); + setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time); #ifndef QT_NO_CLIPBOARD - m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event); + m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event)); #endif handled = true; break; case XCB_SELECTION_NOTIFY: - setTime(((xcb_selection_notify_event_t *)event)->time); + setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time); handled = false; break; case XCB_PROPERTY_NOTIFY: { - xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); if (pn->atom == atom(QXcbAtom::_NET_WORKAREA)) { QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(pn->window); if (virtualDesktop) @@ -1237,7 +1237,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) if (!handled) { if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { - xcb_xfixes_selection_notify_event_t *notify_event = (xcb_xfixes_selection_notify_event_t *)event; + xcb_xfixes_selection_notify_event_t *notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event); setTime(notify_event->timestamp); #ifndef QT_NO_CLIPBOARD m_clipboard->handleXFixesSelectionRequest(notify_event); @@ -1247,10 +1247,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) handled = true; } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) { - updateScreens((xcb_randr_notify_event_t *)event); + updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event)); handled = true; } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { - xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event; + xcb_randr_screen_change_notify_event_t *change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event); for (QXcbScreen *s : qAsConst(m_screens)) { if (s->root() == change_event->root ) s->handleScreenChange(change_event); @@ -1359,7 +1359,7 @@ void QXcbEventReader::run() void QXcbEventReader::addEvent(xcb_generic_event_t *event) { if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE - && ((xcb_client_message_event_t *)event)->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION)) + && (reinterpret_cast<xcb_client_message_event_t *>(event))->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION)) m_connection = 0; m_events << event; } @@ -1425,7 +1425,7 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) event.type = atom(a); event.data.data32[0] = id; - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event)); + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event))); Q_XCB_CALL(xcb_destroy_window(m_connection, eventListener)); xcb_flush(xcb_connection()); } @@ -1445,7 +1445,7 @@ namespace if ((event->response_type & ~0x80) != type) { return false; } else { - xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); if ((pn->window == window) && (pn->atom == atom)) return true; } @@ -1473,7 +1473,7 @@ xcb_timestamp_t QXcbConnection::getTimestamp() event = checkEvent(checker); } - xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); xcb_timestamp_t timestamp = pn->time; free(event); @@ -1497,7 +1497,8 @@ xcb_window_t QXcbConnection::getQtSelectionOwner() { if (!m_qtSelectionOwner) { xcb_screen_t *xcbScreen = primaryVirtualDesktop()->screen(); - int x = 0, y = 0, w = 3, h = 3; + int16_t x = 0, y = 0; + uint16_t w = 3, h = 3; m_qtSelectionOwner = xcb_generate_id(xcb_connection()); Q_XCB_CALL(xcb_create_window(xcb_connection(), XCB_COPY_FROM_PARENT, // depth -- same as root @@ -1686,7 +1687,7 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, for (int j = nextIndex; j < eventqueue->size(); ++j) { xcb_generic_event_t *next = eventqueue->at(j); if (isValid(next) && next->response_type == XCB_CONFIGURE_NOTIFY - && ((xcb_configure_notify_event_t *)next)->event == ((xcb_configure_notify_event_t*)event)->event) + && reinterpret_cast<xcb_configure_notify_event_t *>(next)->event == reinterpret_cast<xcb_configure_notify_event_t *>(event)->event) { return true; } @@ -1715,7 +1716,7 @@ void QXcbConnection::processXcbEvents() (*eventqueue)[i] = 0; if (!(event->response_type & ~0x80)) { - handleXcbError((xcb_generic_error_t *)event); + handleXcbError(reinterpret_cast<xcb_generic_error_t *>(event)); continue; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index f6ba828a15..c9fc27997b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -694,7 +694,7 @@ Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE); #endif #endif -#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) +#define DISPLAY_FROM_XCB(object) (reinterpret_cast<Display *>(object->connection()->xlib_display())) #define CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(object) ((XVisualInfo *)(object->connection()->createVisualInfoForDefaultVisualId())) template<typename T> diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 1c13f8edc2..c175967054 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -103,6 +103,9 @@ #if defined(Q_OS_MACX) #include <IOKit/pwr_mgt/IOPMLib.h> +#include <mach/task.h> +#include <mach/mach_init.h> +#include <CoreFoundation/CFPreferences.h> #endif #include <vector> @@ -137,6 +140,40 @@ static bool debuggerPresent() return pid != 0; #elif defined(Q_OS_WIN) return IsDebuggerPresent(); +#elif defined(Q_OS_MACOS) + auto equals = [](CFStringRef str1, CFStringRef str2) -> bool { + return CFStringCompare(str1, str2, kCFCompareCaseInsensitive) == kCFCompareEqualTo; + }; + + // Check if there is an exception handler for the process: + mach_msg_type_number_t portCount = 0; + exception_mask_t masks[EXC_TYPES_COUNT]; + mach_port_t ports[EXC_TYPES_COUNT]; + exception_behavior_t behaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t flavors[EXC_TYPES_COUNT]; + exception_mask_t mask = EXC_MASK_ALL & ~(EXC_MASK_RESOURCE | EXC_MASK_GUARD); + kern_return_t result = task_get_exception_ports(mach_task_self(), mask, masks, &portCount, + ports, behaviors, flavors); + if (result == KERN_SUCCESS) { + for (mach_msg_type_number_t portIndex = 0; portIndex < portCount; ++portIndex) { + if (MACH_PORT_VALID(ports[portIndex])) { + return true; + } + } + } + + // Ok, no debugger attached. So, let's see if CrashReporter will throw up a dialog. If so, we + // leave it to the OS to do the stack trace. + CFStringRef crashReporterType = static_cast<CFStringRef>( + CFPreferencesCopyAppValue(CFSTR("DialogType"), CFSTR("com.apple.CrashReporter"))); + if (crashReporterType == nullptr) + return true; + + const bool createsStackTrace = + !equals(crashReporterType, CFSTR("server")) && + !equals(crashReporterType, CFSTR("none")); + CFRelease(crashReporterType); + return createsStackTrace; #else // TODO return false; diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro index 8a1e1fd6e3..68b6b28945 100644 --- a/src/tools/bootstrap/bootstrap.pro +++ b/src/tools/bootstrap/bootstrap.pro @@ -40,6 +40,7 @@ SOURCES += \ ../../corelib/global/qlogging.cpp \ ../../corelib/global/qmalloc.cpp \ ../../corelib/global/qnumeric.cpp \ + ../../corelib/global/qoperatingsystemversion.cpp \ ../../corelib/io/qabstractfileengine.cpp \ ../../corelib/io/qbuffer.cpp \ ../../corelib/io/qdatastream.cpp \ @@ -108,7 +109,8 @@ unix:SOURCES += ../../corelib/io/qfilesystemengine_unix.cpp \ ../../corelib/io/qfilesystemiterator_unix.cpp \ ../../corelib/io/qfsfileengine_unix.cpp -win32:SOURCES += ../../corelib/io/qfilesystemengine_win.cpp \ +win32:SOURCES += ../../corelib/global/qoperatingsystemversion_win.cpp \ + ../../corelib/io/qfilesystemengine_win.cpp \ ../../corelib/io/qfilesystemiterator_win.cpp \ ../../corelib/io/qfsfileengine_win.cpp \ ../../corelib/kernel/qcoreapplication_win.cpp \ @@ -119,6 +121,7 @@ mac { ../../corelib/kernel/qcoreapplication_mac.cpp \ ../../corelib/kernel/qcore_mac.cpp OBJECTIVE_SOURCES += \ + ../../corelib/global/qoperatingsystemversion_darwin.mm \ ../../corelib/kernel/qcore_mac_objc.mm \ ../../corelib/kernel/qcore_foundation.mm diff --git a/src/tools/uic/cpp/cppwriteincludes.cpp b/src/tools/uic/cpp/cppwriteincludes.cpp index a99d6adf07..dcbe400224 100644 --- a/src/tools/uic/cpp/cppwriteincludes.cpp +++ b/src/tools/uic/cpp/cppwriteincludes.cpp @@ -114,8 +114,9 @@ void WriteIncludes::acceptUI(DomUI *node) TreeWalker::acceptUI(node); - if (!m_uic->option().includeFile.isEmpty()) - m_globalIncludes.insert(m_uic->option().includeFile, true); + const auto includeFile = m_uic->option().includeFile; + if (!includeFile.isEmpty()) + m_globalIncludes.insert(includeFile); writeHeaders(m_globalIncludes, true); writeHeaders(m_localIncludes, false); @@ -272,10 +273,11 @@ void WriteIncludes::insertInclude(const QString &header, bool global) fprintf(stderr, "%s %s %d\n", Q_FUNC_INFO, qPrintable(header), global); OrderedSet &includes = global ? m_globalIncludes : m_localIncludes; - if (includes.contains(header)) + // Insert (if not already done). + const bool isNewHeader = includes.insert(header).second; + if (!isNewHeader) return; - // Insert. Also remember base name for quick check of suspicious custom plugins - includes.insert(header, false); + // Also remember base name for quick check of suspicious custom plugins const QString lowerBaseName = QFileInfo(header).completeBaseName ().toLower(); m_includeBaseNames.insert(lowerBaseName); } @@ -286,13 +288,11 @@ void WriteIncludes::writeHeaders(const OrderedSet &headers, bool global) const QChar closingQuote = global ? QLatin1Char('>') : QLatin1Char('"'); // Check for the old headers 'qslider.h' and replace by 'QtGui/QSlider' - const OrderedSet::const_iterator cend = headers.constEnd(); - for (OrderedSet::const_iterator sit = headers.constBegin(); sit != cend; ++sit) { - const StringMap::const_iterator hit = m_oldHeaderToNewHeader.constFind(sit.key()); - const bool mapped = hit != m_oldHeaderToNewHeader.constEnd(); - const QString header = mapped ? hit.value() : sit.key(); - if (!QStringRef(&header).trimmed().isEmpty()) - m_output << "#include " << openingQuote << header << closingQuote << QLatin1Char('\n'); + for (const QString &header : headers) { + const QString value = m_oldHeaderToNewHeader.value(header, header); + const auto trimmed = QStringRef(&value).trimmed(); + if (!trimmed.isEmpty()) + m_output << "#include " << openingQuote << trimmed << closingQuote << QLatin1Char('\n'); } } diff --git a/src/tools/uic/cpp/cppwriteincludes.h b/src/tools/uic/cpp/cppwriteincludes.h index 397c6a26e1..7a6a499536 100644 --- a/src/tools/uic/cpp/cppwriteincludes.h +++ b/src/tools/uic/cpp/cppwriteincludes.h @@ -35,6 +35,8 @@ #include <qset.h> #include <qstring.h> +#include <set> + QT_BEGIN_NAMESPACE class QTextStream; @@ -72,7 +74,7 @@ private: void add(const QString &className, bool determineHeader = true, const QString &header = QString(), bool global = false); private: - typedef QMap<QString, bool> OrderedSet; + typedef std::set<QString> OrderedSet; void insertIncludeForClass(const QString &className, QString header = QString(), bool global = false); void insertInclude(const QString &header, bool global); void writeHeaders(const OrderedSet &headers, bool global); diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp index e6fda103fb..bd9f0c6e01 100644 --- a/src/widgets/accessible/simplewidgets.cpp +++ b/src/widgets/accessible/simplewidgets.cpp @@ -468,21 +468,15 @@ QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > QAccessibleDisplay::relations(QAccessible::Relation match /* = QAccessible::AllRelations */) const { QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > rels = QAccessibleWidget::relations(match); - if (match & QAccessible::Labelled) { - QVarLengthArray<QObject *, 4> relatedObjects; - #ifndef QT_NO_SHORTCUT + if (match & QAccessible::Labelled) { if (QLabel *label = qobject_cast<QLabel*>(object())) { - relatedObjects.append(label->buddy()); - } -#endif - for (int i = 0; i < relatedObjects.count(); ++i) { const QAccessible::Relation rel = QAccessible::Labelled; - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(relatedObjects.at(i)); - if (iface) + if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(label->buddy())) rels.append(qMakePair(iface, rel)); } } +#endif return rels; } diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp index 9d8e7c4b66..1a38f43d35 100644 --- a/src/widgets/dialogs/qwizard_win.cpp +++ b/src/widgets/dialogs/qwizard_win.cpp @@ -46,6 +46,7 @@ #include "qwizard.h" #include "qpaintengine.h" #include "qapplication.h" +#include <QtCore/QOperatingSystemVersion> #include <QtCore/QVariant> #include <QtCore/QDebug> #include <QtGui/QMouseEvent> @@ -715,7 +716,7 @@ int QVistaHelper::topOffset() if (vistaState() != VistaAero) return titleBarSize() + 3; static const int aeroOffset = - QSysInfo::WindowsVersion == QSysInfo::WV_WINDOWS7 ? + QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8 ? QStyleHelper::dpiScaled(4) : QStyleHelper::dpiScaled(13); return aeroOffset + titleBarSize(); } diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp index 6e10d18e11..6a9036997c 100644 --- a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp @@ -2575,10 +2575,12 @@ void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet<AnchorData *> & for (const AnchorData *ad : visited) identifyNonFloatItems_helper(ad, &nonFloating); - QSet<QGraphicsLayoutItem *> allItems; - foreach (QGraphicsLayoutItem *item, items) - allItems.insert(item); - m_floatItems[orientation] = allItems - nonFloating; + QSet<QGraphicsLayoutItem *> floatItems; + for (QGraphicsLayoutItem *item : qAsConst(items)) { + if (!nonFloating.contains(item)) + floatItems.insert(item); + } + m_floatItems[orientation] = std::move(floatItems); } diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index dd0edc7c80..02079fb8d5 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -91,12 +91,6 @@ extern Q_GUI_EXPORT bool qt_is_gui_used; extern QClipboard *qt_clipboard; #endif -#if defined (Q_OS_WIN32) || defined (Q_OS_CYGWIN) -extern QSysInfo::WinVersion qt_winver; -#elif defined (Q_OS_MAC) -extern QSysInfo::MacVersion qt_macver; -#endif - typedef QHash<QByteArray, QFont> FontHash; FontHash *qt_app_fonts_hash(); diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 1f17810fc9..6fbc7c9eea 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -84,6 +84,7 @@ #include <qtoolbutton.h> #include <qtreeview.h> #include <qtableview.h> +#include <qoperatingsystemversion.h> #include <qwizard.h> #include <qdebug.h> #include <qlibrary.h> @@ -1310,7 +1311,7 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem bdi->adornment = kThemeAdornmentFocus; if (combo->activeSubControls & QStyle::SC_ComboBoxArrow) bdi->state = kThemeStatePressed; - else if (tds == kThemeStateInactive && QSysInfo::MacintoshVersion < QSysInfo::MV_10_10) + else if (tds == kThemeStateInactive && QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXYosemite) bdi->state = kThemeStateActive; else bdi->state = tds; @@ -1632,7 +1633,7 @@ void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOpti || slider->tickPosition == QSlider::TicksBothSides; tdi->bounds = qt_hirectForQRect(slider->rect); - if (isScrollbar || QSysInfo::MacintoshVersion < QSysInfo::MV_10_10) { + if (isScrollbar || QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXYosemite) { tdi->min = slider->minimum; tdi->max = slider->maximum; tdi->value = slider->sliderPosition; @@ -1944,7 +1945,7 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD const bool button = opt->type == QStyleOption::SO_Button; const bool viewItem = opt->type == QStyleOption::SO_ViewItem; const bool pressed = bdi->state == kThemeStatePressed; - const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10; + const bool usingYosemiteOrLater = QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite; if (button && pressed) { if (bdi->kind == kThemePushButton) { @@ -3579,7 +3580,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter QWindow *window = w && w->window() ? w->window()->windowHandle() : QStyleHelper::styleObjectWindow(opt->styleObject); const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window); - const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10; + const bool usingYosemiteOrLater = QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite; switch (ce) { case CE_HeaderSection: if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) { @@ -3971,7 +3972,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter bool hasIcon = !btn.icon.isNull(); bool hasText = !btn.text.isEmpty(); - if (!hasMenu && QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10) { + if (!hasMenu && QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite) { if (tds == kThemeStatePressed || (tds == kThemeStateActive && ((btn.features & QStyleOptionButton::DefaultButton && !d->autoDefaultButton) @@ -4076,8 +4077,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter QStyleOptionComboBox comboCopy = *cb; comboCopy.direction = Qt::LeftToRight; if (opt->state & QStyle::State_Small) - comboCopy.rect.translate(0, w ? 0 : (QSysInfo::macVersion() >= QSysInfo::MV_10_10 ? 0 : -2)); // Supports Qt Quick Controls - else if (QSysInfo::macVersion() == QSysInfo::MV_10_9) + comboCopy.rect.translate(0, w ? 0 : (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite ? 0 : -2)); // Supports Qt Quick Controls + else if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXMavericks + && QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXYosemite) comboCopy.rect.translate(0, 1); QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w); } @@ -5289,7 +5291,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex QWindow *window = widget && widget->window() ? widget->window()->windowHandle() : QStyleHelper::styleObjectWindow(opt->styleObject); const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window); - const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10; + const bool usingYosemiteOrLater = QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite; switch (cc) { case CC_Slider: case CC_ScrollBar: @@ -5933,7 +5935,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex drawToolbarButtonArrow(tb->rect, tds, cg); } if (tb->state & State_On) { - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10) { + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite) { QWindow *window = 0; if (widget && widget->window()) window = widget->window()->windowHandle(); @@ -6297,7 +6299,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op switch (sc) { case SC_ComboBoxEditField:{ ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi); - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10) + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite) ret.setHeight(ret.height() - 1); break; } case SC_ComboBoxArrow:{ @@ -6756,7 +6758,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_ComboBox: { sz.rwidth() += 50; const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt); - if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_10 || (cb && !cb->editable)) + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXYosemite || (cb && !cb->editable)) sz.rheight() += 2; break; } diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index bf5aad0187..8c91e3a420 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -39,6 +39,7 @@ #include "qwindowsvistastyle_p.h" #include "qwindowsvistastyle_p_p.h" +#include <qoperatingsystemversion.h> #include <qscreen.h> #include <qwindow.h> #include <private/qstyleanimation_p.h> @@ -1752,7 +1753,7 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle theme.stateId = stateId; d->drawBackground(theme); - if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8) { + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) { const QRect gripperBounds = QWindowsXPStylePrivate::scrollBarGripperBounds(flags, widget, &theme); // Draw gripper if there is enough space if (!gripperBounds.isEmpty() && flags & State_Enabled) { diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp index 2a418167f1..9dfd35cadb 100644 --- a/src/widgets/util/qsystemtrayicon.cpp +++ b/src/widgets/util/qsystemtrayicon.cpp @@ -59,6 +59,25 @@ QT_BEGIN_NAMESPACE +static QIcon messageIcon2qIcon(QSystemTrayIcon::MessageIcon icon) +{ + QStyle::StandardPixmap stdIcon; + switch (icon) { + case QSystemTrayIcon::Information: + stdIcon = QStyle::SP_MessageBoxInformation; + break; + case QSystemTrayIcon::Warning: + stdIcon = QStyle::SP_MessageBoxWarning; + break; + case QSystemTrayIcon::Critical: + stdIcon = QStyle::SP_MessageBoxCritical; + break; + case QSystemTrayIcon::NoIcon: + return QIcon(); + } + return QApplication::style()->standardIcon(stdIcon); +} + /*! \class QSystemTrayIcon \brief The QSystemTrayIcon class provides an icon for an application in the system tray. @@ -382,11 +401,29 @@ bool QSystemTrayIcon::supportsMessages() \sa show(), supportsMessages() */ void QSystemTrayIcon::showMessage(const QString& title, const QString& msg, - QSystemTrayIcon::MessageIcon icon, int msecs) + QSystemTrayIcon::MessageIcon msgIcon, int msecs) { Q_D(QSystemTrayIcon); if (d->visible) - d->showMessage_sys(title, msg, icon, msecs); + d->showMessage_sys(title, msg, messageIcon2qIcon(msgIcon), msgIcon, msecs); +} + +/*! + \fn void QSystemTrayIcon::showMessage(const QString &title, const QString &message, const QIcon &icon, int millisecondsTimeoutHint) + + \overload showMessage() + + Shows a balloon message for the entry with the given \a title, \a message, + and custom icon \a icon for the time specified in \a millisecondsTimeoutHint. + + \since 5.9 +*/ +void QSystemTrayIcon::showMessage(const QString &title, const QString &msg, + const QIcon &icon, int msecs) +{ + Q_D(QSystemTrayIcon); + if (d->visible) + d->showMessage_sys(title, msg, icon, QSystemTrayIcon::NoIcon, msecs); } void QSystemTrayIconPrivate::_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason reason) @@ -398,9 +435,9 @@ void QSystemTrayIconPrivate::_q_emitActivated(QPlatformSystemTrayIcon::Activatio ////////////////////////////////////////////////////////////////////// static QBalloonTip *theSolitaryBalloonTip = 0; -void QBalloonTip::showBalloon(QSystemTrayIcon::MessageIcon icon, const QString& title, - const QString& message, QSystemTrayIcon *trayIcon, - const QPoint& pos, int timeout, bool showArrow) +void QBalloonTip::showBalloon(const QIcon &icon, const QString &title, + const QString &message, QSystemTrayIcon *trayIcon, + const QPoint &pos, int timeout, bool showArrow) { hideBalloon(); if (message.isEmpty() && title.isEmpty()) @@ -434,8 +471,8 @@ bool QBalloonTip::isBalloonVisible() return theSolitaryBalloonTip; } -QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title, - const QString& message, QSystemTrayIcon *ti) +QBalloonTip::QBalloonTip(const QIcon &icon, const QString &title, + const QString &message, QSystemTrayIcon *ti) : QWidget(0, Qt::ToolTip), trayIcon(ti), timerId(-1) { setAttribute(Qt::WA_DeleteOnClose); @@ -482,26 +519,10 @@ QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title msgLabel->setFixedSize(limit, msgLabel->heightForWidth(limit)); } - QIcon si; - switch (icon) { - case QSystemTrayIcon::Warning: - si = style()->standardIcon(QStyle::SP_MessageBoxWarning); - break; - case QSystemTrayIcon::Critical: - si = style()->standardIcon(QStyle::SP_MessageBoxCritical); - break; - case QSystemTrayIcon::Information: - si = style()->standardIcon(QStyle::SP_MessageBoxInformation); - break; - case QSystemTrayIcon::NoIcon: - default: - break; - } - QGridLayout *layout = new QGridLayout; - if (!si.isNull()) { + if (!icon.isNull()) { QLabel *iconLabel = new QLabel; - iconLabel->setPixmap(si.pixmap(iconSize, iconSize)); + iconLabel->setPixmap(icon.pixmap(iconSize, iconSize)); iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); iconLabel->setMargin(2); layout->addWidget(iconLabel, 0, 0); @@ -678,52 +699,6 @@ void QSystemTrayIconPrivate::remove_sys_qpa() qpa_sys->cleanup(); } -QRect QSystemTrayIconPrivate::geometry_sys_qpa() const -{ - return qpa_sys->geometry(); -} - -void QSystemTrayIconPrivate::updateIcon_sys_qpa() -{ - qpa_sys->updateIcon(icon); -} - -void QSystemTrayIconPrivate::updateMenu_sys_qpa() -{ - if (menu) { - addPlatformMenu(menu); - qpa_sys->updateMenu(menu->platformMenu()); - } -} - -void QSystemTrayIconPrivate::updateToolTip_sys_qpa() -{ - qpa_sys->updateToolTip(toolTip); -} - -void QSystemTrayIconPrivate::showMessage_sys_qpa(const QString &title, - const QString &message, - QSystemTrayIcon::MessageIcon icon, - int msecs) -{ - QIcon notificationIcon; - switch (icon) { - case QSystemTrayIcon::Information: - notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); - break; - case QSystemTrayIcon::Warning: - notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning); - break; - case QSystemTrayIcon::Critical: - notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical); - break; - default: - break; - } - qpa_sys->showMessage(title, message, notificationIcon, - static_cast<QPlatformSystemTrayIcon::MessageIcon>(icon), msecs); -} - void QSystemTrayIconPrivate::addPlatformMenu(QMenu *menu) const { if (menu->platformMenu()) diff --git a/src/widgets/util/qsystemtrayicon.h b/src/widgets/util/qsystemtrayicon.h index fb238c92b0..918dd0478e 100644 --- a/src/widgets/util/qsystemtrayicon.h +++ b/src/widgets/util/qsystemtrayicon.h @@ -101,6 +101,7 @@ public Q_SLOTS: void setVisible(bool visible); inline void show() { setVisible(true); } inline void hide() { setVisible(false); } + void showMessage(const QString &title, const QString &msg, const QIcon &icon, int msecs = 10000); void showMessage(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 10000); diff --git a/src/widgets/util/qsystemtrayicon_p.h b/src/widgets/util/qsystemtrayicon_p.h index 79e824f4b7..3f5cab40be 100644 --- a/src/widgets/util/qsystemtrayicon_p.h +++ b/src/widgets/util/qsystemtrayicon_p.h @@ -84,7 +84,8 @@ public: void updateToolTip_sys(); void updateMenu_sys(); QRect geometry_sys() const; - void showMessage_sys(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon, int secs); + void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon, + QSystemTrayIcon::MessageIcon msgIcon, int msecs); static bool isSystemTrayAvailable_sys(); static bool supportsMessages_sys(); @@ -101,11 +102,7 @@ public: private: void install_sys_qpa(); void remove_sys_qpa(); - void updateIcon_sys_qpa(); - void updateToolTip_sys_qpa(); - void updateMenu_sys_qpa(); - QRect geometry_sys_qpa() const; - void showMessage_sys_qpa(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon, int secs); + void addPlatformMenu(QMenu *menu) const; }; @@ -113,16 +110,16 @@ class QBalloonTip : public QWidget { Q_OBJECT public: - static void showBalloon(QSystemTrayIcon::MessageIcon icon, const QString& title, - const QString& msg, QSystemTrayIcon *trayIcon, - const QPoint& pos, int timeout, bool showArrow = true); + static void showBalloon(const QIcon &icon, const QString &title, + const QString &msg, QSystemTrayIcon *trayIcon, + const QPoint &pos, int timeout, bool showArrow = true); static void hideBalloon(); static bool isBalloonVisible(); static void updateBalloonPosition(const QPoint& pos); private: - QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title, - const QString& msg, QSystemTrayIcon *trayIcon); + QBalloonTip(const QIcon &icon, const QString &title, + const QString &msg, QSystemTrayIcon *trayIcon); ~QBalloonTip(); void balloon(const QPoint&, int, bool); diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp index 643f17a5fe..8399732a4a 100644 --- a/src/widgets/util/qsystemtrayicon_qpa.cpp +++ b/src/widgets/util/qsystemtrayicon_qpa.cpp @@ -76,7 +76,7 @@ void QSystemTrayIconPrivate::remove_sys() QRect QSystemTrayIconPrivate::geometry_sys() const { if (qpa_sys) - return geometry_sys_qpa(); + return qpa_sys->geometry(); else return QRect(); } @@ -84,19 +84,21 @@ QRect QSystemTrayIconPrivate::geometry_sys() const void QSystemTrayIconPrivate::updateIcon_sys() { if (qpa_sys) - updateIcon_sys_qpa(); + qpa_sys->updateIcon(icon); } void QSystemTrayIconPrivate::updateMenu_sys() { - if (qpa_sys) - updateMenu_sys_qpa(); + if (qpa_sys && menu) { + addPlatformMenu(menu); + qpa_sys->updateMenu(menu->platformMenu()); + } } void QSystemTrayIconPrivate::updateToolTip_sys() { if (qpa_sys) - updateToolTip_sys_qpa(); + qpa_sys->updateToolTip(toolTip); } bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys() @@ -118,10 +120,11 @@ bool QSystemTrayIconPrivate::supportsMessages_sys() } void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message, - QSystemTrayIcon::MessageIcon icon, int msecs) + const QIcon &icon, QSystemTrayIcon::MessageIcon msgIcon, int msecs) { if (qpa_sys) - showMessage_sys_qpa(title, message, icon, msecs); + qpa_sys->showMessage(title, message, icon, + static_cast<QPlatformSystemTrayIcon::MessageIcon>(msgIcon), msecs); } QT_END_NAMESPACE diff --git a/src/widgets/util/qsystemtrayicon_win.cpp b/src/widgets/util/qsystemtrayicon_win.cpp index 2da24e482b..638d2050fb 100644 --- a/src/widgets/util/qsystemtrayicon_win.cpp +++ b/src/widgets/util/qsystemtrayicon_win.cpp @@ -81,11 +81,14 @@ struct Q_NOTIFYICONIDENTIFIER { # define NIN_BALLOONTIMEOUT (WM_USER + 4) # define NIN_BALLOONUSERCLICK (WM_USER + 5) # define NIF_SHOWTIP 0x00000080 +# define NIIF_LARGE_ICON 0x00000020 # define NOTIFYICON_VERSION_4 4 #endif #define Q_MSGFLT_ALLOW 1 +Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &); + typedef HRESULT (WINAPI *PtrShell_NotifyIconGetRect)(const Q_NOTIFYICONIDENTIFIER* identifier, RECT* iconLocation); typedef BOOL (WINAPI *PtrChangeWindowMessageFilter)(UINT message, DWORD dwFlag); typedef BOOL (WINAPI *PtrChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD action, void* pChangeFilterStruct); @@ -107,7 +110,7 @@ public: ~QSystemTrayIconSys(); bool trayMessage(DWORD msg); void setIconContents(NOTIFYICONDATA &data); - bool showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs); + bool showMessage(const QString &title, const QString &message, const QIcon &icon, uint uSecs); QRect findIconGeometry(UINT iconId); HICON createIcon(); bool winEvent(MSG *m, long *result); @@ -184,7 +187,7 @@ static inline HWND createTrayIconMessageWindow() QSystemTrayIconSys::QSystemTrayIconSys(HWND hwnd, QSystemTrayIcon *object) : m_hwnd(hwnd), hIcon(0), q(object) - , notifyIconSize(NOTIFYICONDATA_V2_SIZE), version(NOTIFYICON_VERSION) + , notifyIconSize(sizeof(NOTIFYICONDATA)), version(NOTIFYICON_VERSION_4) , ignoreNextMouseRelease(false) { @@ -237,11 +240,7 @@ void QSystemTrayIconSys::setIconContents(NOTIFYICONDATA &tnd) qStringToLimitedWCharArray(tip, tnd.szTip, sizeof(tnd.szTip)/sizeof(wchar_t)); } -#ifndef NIIF_LARGE_ICON -# define NIIF_LARGE_ICON 0x00000020 -#endif - -bool QSystemTrayIconSys::showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs) +bool QSystemTrayIconSys::showMessage(const QString &title, const QString &message, const QIcon &icon, uint uSecs) { NOTIFYICONDATA tnd; memset(&tnd, 0, notifyIconSize); @@ -249,23 +248,32 @@ bool QSystemTrayIconSys::showMessage(const QString &title, const QString &messag qStringToLimitedWCharArray(title, tnd.szInfoTitle, 64); tnd.uID = q_uNOTIFYICONID; - switch (type) { - case QSystemTrayIcon::Information: + tnd.dwInfoFlags = NIIF_USER; + + HICON *phIcon = &tnd.hIcon; + QSize size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + if (version == NOTIFYICON_VERSION_4) { + const QSize largeIcon(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); + QSize more = icon.actualSize(largeIcon); + if (more.height() > (largeIcon.height() * 3/4) || more.width() > (largeIcon.width() * 3/4)) { + tnd.dwInfoFlags |= NIIF_LARGE_ICON; + size = largeIcon; + } + phIcon = &tnd.hBalloonIcon; + } + QPixmap pm = icon.pixmap(size); + if (pm.isNull()) { tnd.dwInfoFlags = NIIF_INFO; - break; - case QSystemTrayIcon::Warning: - tnd.dwInfoFlags = NIIF_WARNING; - break; - case QSystemTrayIcon::Critical: - tnd.dwInfoFlags = NIIF_ERROR; - break; - case QSystemTrayIcon::NoIcon: - tnd.dwInfoFlags = hIcon ? NIIF_USER : NIIF_NONE; - break; + } else { + if (pm.size() != size) { + qWarning("QSystemTrayIcon::showMessage: Wrong icon size (%dx%d), please add standard one: %dx%d", + pm.size().width(), pm.size().height(), size.width(), size.height()); + pm = pm.scaled(size, Qt::IgnoreAspectRatio); + } + *phIcon = qt_pixmapToWinHICON(pm); } - if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) - tnd.dwInfoFlags |= NIIF_LARGE_ICON; tnd.cbSize = notifyIconSize; + tnd.uVersion = version; tnd.hWnd = m_hwnd; tnd.uTimeout = uSecs; tnd.uFlags = NIF_INFO | NIF_SHOWTIP; @@ -296,8 +304,6 @@ bool QSystemTrayIconSys::trayMessage(DWORD msg) return success; } -Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &); - HICON QSystemTrayIconSys::createIcon() { const HICON oldIcon = hIcon; @@ -509,7 +515,8 @@ QRect QSystemTrayIconSys::findIconGeometry(UINT iconId) void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &messageIn, - QSystemTrayIcon::MessageIcon type, + const QIcon &icon, + QSystemTrayIcon::MessageIcon, int timeOut) { if (!sys || !allowsMessages()) @@ -522,7 +529,7 @@ void QSystemTrayIconPrivate::showMessage_sys(const QString &title, if (message.isEmpty() && !title.isEmpty()) message.append(QLatin1Char(' ')); - sys->showMessage(title, message, type, uSecs); + sys->showMessage(title, message, icon, uSecs); } QRect QSystemTrayIconPrivate::geometry_sys() const diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp index ea0604b6ed..20ab0f6377 100644 --- a/src/widgets/util/qsystemtrayicon_x11.cpp +++ b/src/widgets/util/qsystemtrayicon_x11.cpp @@ -284,7 +284,7 @@ void QSystemTrayIconPrivate::install_sys() QRect QSystemTrayIconPrivate::geometry_sys() const { if (qpa_sys) - return geometry_sys_qpa(); + return qpa_sys->geometry(); if (!sys) return QRect(); return sys->globalGeometry(); @@ -307,7 +307,7 @@ void QSystemTrayIconPrivate::remove_sys() void QSystemTrayIconPrivate::updateIcon_sys() { if (qpa_sys) { - updateIcon_sys_qpa(); + qpa_sys->updateIcon(icon); return; } if (sys) @@ -316,14 +316,16 @@ void QSystemTrayIconPrivate::updateIcon_sys() void QSystemTrayIconPrivate::updateMenu_sys() { - if (qpa_sys) - updateMenu_sys_qpa(); + if (qpa_sys && menu) { + addPlatformMenu(menu); + qpa_sys->updateMenu(menu->platformMenu()); + } } void QSystemTrayIconPrivate::updateToolTip_sys() { if (qpa_sys) { - updateToolTip_sys_qpa(); + qpa_sys->updateToolTip(toolTip); return; } if (!sys) @@ -357,10 +359,11 @@ bool QSystemTrayIconPrivate::supportsMessages_sys() } void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message, - QSystemTrayIcon::MessageIcon icon, int msecs) + const QIcon &icon, QSystemTrayIcon::MessageIcon msgIcon, int msecs) { if (qpa_sys) { - showMessage_sys_qpa(title, message, icon, msecs); + qpa_sys->showMessage(title, message, icon, + static_cast<QPlatformSystemTrayIcon::MessageIcon>(msgIcon), msecs); return; } if (!sys) |