summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qglobal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/global/qglobal.cpp')
-rw-r--r--src/corelib/global/qglobal.cpp197
1 files changed, 162 insertions, 35 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 78ad2a5421..4ab5bd2edb 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -47,11 +47,15 @@
#include "qoperatingsystemversion.h"
#include "qoperatingsystemversion_p.h"
#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) || defined(Q_OS_WINRT)
-#include "qoperatingsystemversion_win_p.h"
-#endif
+# include "qoperatingsystemversion_win_p.h"
+# ifndef Q_OS_WINRT
+# include "private/qwinregistry_p.h"
+# endif
+#endif // Q_OS_WIN || Q_OS_CYGWIN
#include <private/qlocale_tools_p.h>
#include <qmutex.h>
+#include <QtCore/private/qlocking_p.h>
#include <stdlib.h>
#include <limits.h>
@@ -1152,12 +1156,12 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value));
\sa QT_VERSION_STR, QLibraryInfo::version()
*/
-const char *qVersion() Q_DECL_NOTHROW
+const char *qVersion() noexcept
{
return QT_VERSION_STR;
}
-bool qSharedBuild() Q_DECL_NOTHROW
+bool qSharedBuild() noexcept
{
#ifdef QT_SHARED
return true;
@@ -1903,6 +1907,42 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \macro Q_PROCESSOR_RISCV
+ \relates <QtGlobal>
+ \since 5.13
+
+ Defined if the application is compiled for RISC-V processors. Qt currently
+ supports two RISC-V variants: \l Q_PROCESSOR_RISCV_32 and \l
+ Q_PROCESSOR_RISCV_64.
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+
+/*!
+ \macro Q_PROCESSOR_RISCV_32
+ \relates <QtGlobal>
+ \since 5.13
+
+ Defined if the application is compiled for 32-bit RISC-V processors. The \l
+ Q_PROCESSOR_RISCV macro is also defined when Q_PROCESSOR_RISCV_32 is
+ defined.
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+
+/*!
+ \macro Q_PROCESSOR_RISCV_64
+ \relates <QtGlobal>
+ \since 5.13
+
+ Defined if the application is compiled for 64-bit RISC-V processors. The \l
+ Q_PROCESSOR_RISCV macro is also defined when Q_PROCESSOR_RISCV_64 is
+ defined.
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+
+/*!
\macro Q_PROCESSOR_S390
\relates <QtGlobal>
@@ -2149,12 +2189,33 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion()
QT_WARNING_POP
#endif
+static QString readVersionRegistryString(const wchar_t *subKey)
+{
+#if !defined(QT_BUILD_QMAKE) && !defined(Q_OS_WINRT)
+ return QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)")
+ .stringValue(subKey);
+#else
+ Q_UNUSED(subKey);
+ return QString();
+#endif
+}
+
+static inline QString windows10ReleaseId()
+{
+ return readVersionRegistryString(L"ReleaseId");
+}
+
+static inline QString windows7Build()
+{
+ return readVersionRegistryString(L"CurrentBuild");
+}
+
static QString winSp_helper()
{
const auto osv = qWindowsVersionInfo();
const qint16 major = osv.wServicePackMajor;
if (major) {
- QString sp = QStringLiteral(" SP ") + QString::number(major);
+ QString sp = QStringLiteral("SP ") + QString::number(major);
const qint16 minor = osv.wServicePackMinor;
if (minor)
sp += QLatin1Char('.') + QString::number(minor);
@@ -2867,19 +2928,34 @@ QString QSysInfo::prettyProductName()
{
#if (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
const auto version = QOperatingSystemVersion::current();
+ const int majorVersion = version.majorVersion();
+ const QString versionString = QString::number(majorVersion) + QLatin1Char('.')
+ + QString::number(version.minorVersion());
+ QString result = version.name() + QLatin1Char(' ');
const char *name = osVer_helper(version);
- if (name)
- 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 version.name() + QLatin1Char(' ')
- + QString::number(version.majorVersion()) + QLatin1Char('.')
- + QString::number(version.minorVersion());
+ if (!name)
+ return result + versionString;
+ result += QLatin1String(name);
+# if !defined(Q_OS_WIN) || defined(Q_OS_WINRT)
+ return result + QLatin1String(" (") + versionString + QLatin1Char(')');
+# else
+ // (resembling winver.exe): Windows 10 "Windows 10 Version 1809"
+ if (majorVersion >= 10) {
+ const auto releaseId = windows10ReleaseId();
+ if (!releaseId.isEmpty())
+ result += QLatin1String(" Version ") + releaseId;
+ return result;
+ }
+ // Windows 7: "Windows 7 Version 6.1 (Build 7601: Service Pack 1)"
+ result += QLatin1String(" Version ") + versionString + QLatin1String(" (");
+ const auto build = windows7Build();
+ if (!build.isEmpty())
+ result += QLatin1String("Build ") + build;
+ const auto servicePack = winSp_helper();
+ if (!servicePack.isEmpty())
+ result += QLatin1String(": ") + servicePack;
+ return result + QLatin1Char(')');
+# endif // Windows
#elif defined(Q_OS_HAIKU)
return QLatin1String("Haiku ") + productVersion();
#elif defined(Q_OS_UNIX)
@@ -2921,6 +2997,7 @@ QString QSysInfo::machineHostName()
struct utsname u;
if (uname(&u) == 0)
return QString::fromLocal8Bit(u.nodename);
+ return QString();
#else
# ifdef Q_OS_WIN
// Important: QtNetwork depends on machineHostName() initializing ws2_32.dll
@@ -2933,7 +3010,6 @@ QString QSysInfo::machineHostName()
hostName[sizeof(hostName) - 1] = '\0';
return QString::fromLocal8Bit(hostName);
#endif
- return QString();
}
#endif // QT_BOOTSTRAPPED
@@ -2998,6 +3074,7 @@ QByteArray QSysInfo::machineUniqueId()
}
#elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
// Let's poke at the registry
+ // ### Qt 6: Use new helpers from qwinregistry.cpp (once bootstrap builds are obsolete)
HKEY key = NULL;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ | KEY_WOW64_64KEY, &key)
== ERROR_SUCCESS) {
@@ -3224,7 +3301,7 @@ QByteArray QSysInfo::bootUniqueId()
The Q_CHECK_PTR macro calls this function if an allocation check
fails.
*/
-void qt_check_pointer(const char *n, int l) Q_DECL_NOTHROW
+void qt_check_pointer(const char *n, int l) noexcept
{
// make separate printing calls so that the first one may flush;
// the second one could want to allocate memory (fputs prints a
@@ -3251,7 +3328,7 @@ void qBadAlloc()
Allows you to call std::terminate() without including <exception>.
Called internally from QT_TERMINATE_ON_EXCEPTION
*/
-Q_NORETURN void qTerminate() Q_DECL_NOTHROW
+Q_NORETURN void qTerminate() noexcept
{
std::terminate();
}
@@ -3260,7 +3337,7 @@ Q_NORETURN void qTerminate() Q_DECL_NOTHROW
/*
The Q_ASSERT macro calls this function when the test fails.
*/
-void qt_assert(const char *assertion, const char *file, int line) Q_DECL_NOTHROW
+void qt_assert(const char *assertion, const char *file, int line) noexcept
{
QMessageLogger(file, line, nullptr).fatal("ASSERT: \"%s\" in file %s, line %d", assertion, file, line);
}
@@ -3268,7 +3345,7 @@ void qt_assert(const char *assertion, const char *file, int line) Q_DECL_NOTHROW
/*
The Q_ASSERT_X macro calls this function when the test fails.
*/
-void qt_assert_x(const char *where, const char *what, const char *file, int line) Q_DECL_NOTHROW
+void qt_assert_x(const char *where, const char *what, const char *file, int line) noexcept
{
QMessageLogger(file, line, nullptr).fatal("ASSERT failure in %s: \"%s\", file %s, line %d", where, what, file, line);
}
@@ -3315,7 +3392,7 @@ static QBasicMutex environmentMutex;
*/
void qTzSet()
{
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
#if defined(Q_OS_WIN)
_tzset();
#else
@@ -3329,7 +3406,7 @@ void qTzSet()
*/
time_t qMkTime(struct tm *when)
{
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
return mktime(when);
}
@@ -3361,7 +3438,7 @@ time_t qMkTime(struct tm *when)
*/
QByteArray qgetenv(const char *varName)
{
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
#ifdef Q_CC_MSVC
size_t requiredSize = 0;
QByteArray buffer;
@@ -3429,7 +3506,7 @@ QByteArray qgetenv(const char *varName)
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
{
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
QVarLengthArray<wchar_t, 32> wname(int(strlen(varName)) + 1);
for (int i = 0; i < wname.size(); ++i) // wname.size() is correct: will copy terminating null
wname[i] = uchar(varName[i]);
@@ -3475,9 +3552,9 @@ QString qEnvironmentVariable(const char *varName)
\sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet()
*/
-bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT
+bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
{
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
#ifdef Q_CC_MSVC
// we provide a buffer that can only hold the empty string, so
// when the env.var isn't empty, we'll get an ERANGE error (buffer
@@ -3510,13 +3587,13 @@ bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT
\sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet()
*/
-int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT
+int qEnvironmentVariableIntValue(const char *varName, bool *ok) noexcept
{
static const int NumBinaryDigitsPerOctalDigit = 3;
static const int MaxDigitsForOctalInt =
(std::numeric_limits<uint>::digits + NumBinaryDigitsPerOctalDigit - 1) / NumBinaryDigitsPerOctalDigit;
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
#ifdef Q_CC_MSVC
// we provide a buffer that can hold any int value:
char buffer[MaxDigitsForOctalInt + 2]; // +1 for NUL +1 for optional '-'
@@ -3579,15 +3656,15 @@ int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT
\sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsEmpty()
*/
-bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT
+bool qEnvironmentVariableIsSet(const char *varName) noexcept
{
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
#ifdef Q_CC_MSVC
size_t requiredSize = 0;
(void)getenv_s(&requiredSize, 0, 0, varName);
return requiredSize != 0;
#else
- return ::getenv(varName) != 0;
+ return ::getenv(varName) != nullptr;
#endif
}
@@ -3611,7 +3688,7 @@ bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT
*/
bool qputenv(const char *varName, const QByteArray& value)
{
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
#if defined(Q_CC_MSVC)
return _putenv_s(varName, value.constData()) == 0;
#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_HAIKU)
@@ -3642,7 +3719,7 @@ bool qputenv(const char *varName, const QByteArray& value)
*/
bool qunsetenv(const char *varName)
{
- QMutexLocker locker(&environmentMutex);
+ const auto locker = qt_scoped_lock(environmentMutex);
#if defined(Q_CC_MSVC)
return _putenv_s(varName, "") == 0;
#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_BSD4) || defined(Q_OS_HAIKU)
@@ -3781,6 +3858,56 @@ bool qunsetenv(const char *varName)
*/
/*!
+ \fn template <typename T, typename U = T> T qExchange(T &obj, U &&newValue)
+ \relates <QtGlobal>
+ \since 5.14
+
+ Replaces the value of \a obj with \a newValue and returns the old value of \a obj.
+
+ This is Qt's implementation of std::exchange(). It differs from std::exchange()
+ only in that it is \c constexpr already in C++14, and available on all supported
+ compilers.
+
+ Here is how to use qExchange() to implement move constructors:
+ \code
+ MyClass(MyClass &&other)
+ : m_pointer{qExchange(other.m_pointer, nullptr)},
+ m_int{qExchange(other.m_int, 0)},
+ m_vector{std::move(other.m_vector)},
+ ...
+ \endcode
+
+ For members of class type, we can use std::move(), as their move-constructor will
+ do the right thing. But for scalar types such as raw pointers or integer type, move
+ is the same as copy, which, particularly for pointers, is not what we expect. So, we
+ cannot use std::move() for such types, but we can use std::exchange()/qExchange() to
+ make sure the source object's member is already reset by the time we get to the
+ initialization of our next data member, which might come in handy if the constructor
+ exits with an exception.
+
+ Here is how to use qExchange() to write a loop that consumes the collection it
+ iterates over:
+ \code
+ for (auto &e : qExchange(collection, {})
+ doSomethingWith(e);
+ \endcode
+
+ Which is equivalent to the following, much more verbose code:
+ \code
+ {
+ auto tmp = std::move(collection);
+ collection = {}; // or collection.clear()
+ for (auto &e : tmp)
+ doSomethingWith(e);
+ } // destroys 'tmp'
+ \endcode
+
+ This is perfectly safe, as the for-loop keeps the result of qExchange() alive for as
+ long as the loop runs, saving the declaration of a temporary variable. Be aware, though,
+ that qExchange() returns a non-const object, so Qt containers may detach.
+*/
+
+/*!
\macro QT_TR_NOOP(sourceText)
\relates <QtGlobal>