diff options
Diffstat (limited to 'src')
147 files changed, 3046 insertions, 821 deletions
diff --git a/src/corelib/configure.json b/src/corelib/configure.json index 8cd73d6ce4..9f9512942a 100644 --- a/src/corelib/configure.json +++ b/src/corelib/configure.json @@ -15,7 +15,8 @@ "posix-ipc": { "type": "boolean", "name": "ipc_posix" }, "pps": { "type": "boolean", "name": "qqnx_pps" }, "slog2": "boolean", - "syslog": "boolean" + "syslog": "boolean", + "trace": { "type": "optionalString", "values": [ "etw", "lttng", "no", "yes" ] } } }, @@ -147,6 +148,18 @@ "-lrt" ] }, + "lttng-ust": { + "label": "lttng-ust", + "test": { + "include": "lttng/ust-events.h", + "main": "lttng_session_destroy(nullptr);" + }, + "sources": [ + { "type": "pkgConfig", "args": "lttng-ust" }, + "-llttng-ust" + ], + "use": "libdl" + }, "pcre2": { "label": "PCRE2", "test": { @@ -858,6 +871,22 @@ "section": "Utilities", "output": [ "publicFeature" ] }, + "lttng": { + "label": "LTTNG", + "autoDetect": false, + "enable": "input.trace == 'lttng' || (input.trace =='yes' && config.linux)", + "disable": "input.trace == 'etw' || input.trace =='no'", + "condition": "config.linux && libs.lttng-ust", + "output": [ "privateFeature" ] + }, + "etw": { + "label": "ETW", + "autoDetect": false, + "enable": "input.trace == 'etw' || (input.trace == 'yes' && config.win32)", + "disable": "input.trace == 'lttng' || input.trace == 'no'", + "condition": "config.win32", + "output": [ "privateFeature" ] + }, "topleveldomain": { "label": "QUrl::topLevelDomain()", "purpose": "Provides support for extracting the top level domain from URLs. @@ -908,6 +937,11 @@ Please apply the patch corresponding to your Standard Library vendor, found in "iconv", "icu", { + "message": "Tracing backend", + "type": "firstAvailableFeature", + "args": "etw lttng" + }, + { "section": "Logging backends", "entries": [ "journald", "syslog", "slog2" diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index 6dc4af1bfe..2079d2117f 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -6,6 +6,9 @@ MODULE = core # not corelib, as per project file MODULE_CONFIG = moc resources !isEmpty(QT_NAMESPACE): MODULE_DEFINES = QT_NAMESPACE=$$QT_NAMESPACE +TRACEPOINT_PROVIDER = $$PWD/qtcore.tracepoints +CONFIG += qt_tracepoints + CONFIG += $$MODULE_CONFIG DEFINES += $$MODULE_DEFINES DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH @@ -35,13 +38,12 @@ include(thread/thread.pri) include(tools/tools.pri) include(io/io.pri) include(itemmodels/itemmodels.pri) -include(json/json.pri) include(plugin/plugin.pri) include(kernel/kernel.pri) include(codecs/codecs.pri) +include(serialization/serialization.pri) include(statemachine/statemachine.pri) include(mimetypes/mimetypes.pri) -include(xml/xml.pri) win32 { LIBS_PRIVATE += -lws2_32 diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index 0df593941d..86ef1a2613 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -78,6 +78,7 @@ #define QT_FEATURE_cxx11_random (QT_HAS_INCLUDE(<random>) ? 1 : -1) #define QT_NO_DATASTREAM #define QT_FEATURE_datetimeparser -1 +#define QT_FEATURE_etw -1 #define QT_FEATURE_getauxval (QT_HAS_INCLUDE(<sys/auxv.h>) ? 1 : -1) #define QT_FEATURE_getentropy -1 #define QT_NO_GEOM_VARIANT @@ -92,6 +93,7 @@ #else # define QT_FEATURE_linkat -1 #endif +#define QT_FEATURE_lttng -1 #define QT_NO_QOBJECT #define QT_FEATURE_process -1 #define QT_FEATURE_regularexpression -1 diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp index 3046a47292..fd608efe55 100644 --- a/src/corelib/global/qfloat16.cpp +++ b/src/corelib/global/qfloat16.cpp @@ -178,6 +178,7 @@ static void qFloatFromFloat16_fast(float *, const quint16 *, qsizetype) Q_DECL_N #endif /*! \since 5.11 + \relates <QFloat16> Converts \a len floats from \a in to qfloat16 and stores them in \a out. Both \a in and \a out must have \a len allocated entries. @@ -193,6 +194,7 @@ Q_CORE_EXPORT void qFloatToFloat16(qfloat16 *out, const float *in, qsizetype len /*! \since 5.11 + \relates <QFloat16> Converts \a len qfloat16 from \a in to floats and stores them in \a out. Both \a in and \a out must have \a len allocated entries. diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 7764707de0..aa9446221b 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -88,6 +88,11 @@ #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) # define QT_NO_UNSHARABLE_CONTAINERS +# define QT6_VIRTUAL virtual +# define QT6_NOT_VIRTUAL +#else +# define QT6_VIRTUAL +# define QT6_NOT_VIRTUAL virtual #endif /* These two macros makes it possible to turn the builtin line expander into a diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index a352e39ef0..9b86a16516 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2018 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -58,8 +58,6 @@ #if defined(Q_CC_MSVC) # include <intrin.h> -#elif defined(Q_CC_INTEL) -# include <immintrin.h> // for _addcarry_u<nn> #endif #if defined(Q_CC_MSVC) @@ -164,10 +162,33 @@ Q_DECL_CONST_FUNCTION static inline bool qt_is_finite(float f) } #ifndef Q_CLANG_QDOC -// -// Unsigned overflow math -// namespace { +// Overflow math. +// This provides efficient implementations for int, unsigned, qsizetype and +// size_t. Implementations for 8- and 16-bit types will work but may not be as +// efficient. Implementations for 64-bit may be missing on 32-bit platforms. + +#if (defined(Q_CC_GNU) && (Q_CC_GNU >= 500) || defined(Q_CC_INTEL)) || QT_HAS_BUILTIN(__builtin_add_overflowx) +// GCC 5, ICC 18, and Clang 3.8 have builtins to detect overflows + +template <typename T> inline +typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type +add_overflow(T v1, T v2, T *r) +{ return __builtin_add_overflow(v1, v2, r); } + +template <typename T> inline +typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type +sub_overflow(T v1, T v2, T *r) +{ return __builtin_sub_overflow(v1, v2, r); } + +template <typename T> inline +typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type +mul_overflow(T v1, T v2, T *r) +{ return __builtin_mul_overflow(v1, v2, r); } + +#else +// Generic implementations + template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type add_overflow(T v1, T v2, T *r) { @@ -176,69 +197,92 @@ add_overflow(T v1, T v2, T *r) return v1 > T(v1 + v2); } +template <typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type +add_overflow(T v1, T v2, T *r) +{ + // Here's how we calculate the overflow: + // 1) unsigned addition is well-defined, so we can always execute it + // 2) conversion from unsigned back to signed is implementation- + // defined and in the implementations we use, it's a no-op. + // 3) signed integer overflow happens if the sign of the two input operands + // is the same but the sign of the result is different. In other words, + // the sign of the result must be the same as the sign of either + // operand. + + using U = typename std::make_unsigned<T>::type; + *r = T(U(v1) + U(v2)); + + // If int is two's complement, assume all integer types are too. + if (std::is_same<int32_t, int>::value) { + // Two's complement equivalent (generates slightly shorter code): + // x ^ y is negative if x and y have different signs + // x & y is negative if x and y are negative + // (x ^ z) & (y ^ z) is negative if x and z have different signs + // AND y and z have different signs + return ((v1 ^ *r) & (v2 ^ *r)) < 0; + } + + bool s1 = (v1 < 0); + bool s2 = (v2 < 0); + bool sr = (*r < 0); + return s1 != sr && s2 != sr; + // also: return s1 == s2 && s1 != sr; +} + template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type +sub_overflow(T v1, T v2, T *r) +{ + // unsigned subtractions are well-defined + *r = v1 - v2; + return v1 < v2; +} + +template <typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type +sub_overflow(T v1, T v2, T *r) +{ + // See above for explanation. This is the same with some signs reversed. + // We can't use add_overflow(v1, -v2, r) because it would be UB if + // v2 == std::numeric_limits<T>::min(). + + using U = typename std::make_unsigned<T>::type; + *r = T(U(v1) - U(v2)); + + if (std::is_same<int32_t, int>::value) + return ((v1 ^ *r) & (~v2 ^ *r)) < 0; + + bool s1 = (v1 < 0); + bool s2 = !(v2 < 0); + bool sr = (*r < 0); + return s1 != sr && s2 != sr; + // also: return s1 == s2 && s1 != sr; +} + +template <typename T> inline +typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type mul_overflow(T v1, T v2, T *r) { // use the next biggest type // Note: for 64-bit systems where __int128 isn't supported, this will cause an error. - // A fallback is present below. - typedef typename QIntegerForSize<sizeof(T) * 2>::Unsigned Larger; + using LargerInt = QIntegerForSize<sizeof(T) * 2>; + using Larger = typename std::conditional<std::is_signed<T>::value, + typename LargerInt::Signed, typename LargerInt::Unsigned>::type; Larger lr = Larger(v1) * Larger(v2); *r = T(lr); - return lr > std::numeric_limits<T>::max(); + return lr > std::numeric_limits<T>::max() || lr < std::numeric_limits<T>::min(); } -#if defined(__SIZEOF_INT128__) -# define HAVE_MUL64_OVERFLOW -#endif - -// GCC 5 and Clang have builtins to detect overflows -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_uadd_overflow) +# if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86) +// We can use intrinsics for the unsigned operations with MSVC template <> inline bool add_overflow(unsigned v1, unsigned v2, unsigned *r) -{ return __builtin_uadd_overflow(v1, v2, r); } -#endif -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_uaddl_overflow) -template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r) -{ return __builtin_uaddl_overflow(v1, v2, r); } -#endif -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_uaddll_overflow) -template <> inline bool add_overflow(unsigned long long v1, unsigned long long v2, unsigned long long *r) -{ return __builtin_uaddll_overflow(v1, v2, r); } -#endif +{ return _addcarry_u32(0, v1, v2, r); } -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_umul_overflow) -template <> inline bool mul_overflow(unsigned v1, unsigned v2, unsigned *r) -{ return __builtin_umul_overflow(v1, v2, r); } -#endif -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_umull_overflow) -template <> inline bool mul_overflow(unsigned long v1, unsigned long v2, unsigned long *r) -{ return __builtin_umull_overflow(v1, v2, r); } -#endif -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_umulll_overflow) -template <> inline bool mul_overflow(unsigned long long v1, unsigned long long v2, unsigned long long *r) -{ return __builtin_umulll_overflow(v1, v2, r); } -# define HAVE_MUL64_OVERFLOW -#endif +// 32-bit mul_overflow is fine with the generic code above -#if (defined(Q_CC_MSVC) || defined(Q_CC_INTEL)) && defined(Q_PROCESSOR_X86) && !QT_HAS_BUILTIN(__builtin_uadd_overflow) -template <> inline bool add_overflow(unsigned v1, unsigned v2, unsigned *r) -{ return _addcarry_u32(0, v1, v2, r); } -# ifdef Q_CC_MSVC // longs are 32-bit -template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r) -{ return _addcarry_u32(0, v1, v2, reinterpret_cast<unsigned *>(r)); } -# endif -#endif -#if (defined(Q_CC_MSVC) || defined(Q_CC_INTEL)) && defined(Q_PROCESSOR_X86_64) && !QT_HAS_BUILTIN(__builtin_uadd_overflow) +# if defined(Q_PROCESSOR_X86_64) template <> inline bool add_overflow(quint64 v1, quint64 v2, quint64 *r) { return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r)); } -# ifndef Q_CC_MSVC // longs are 64-bit -template <> inline bool add_overflow(unsigned long v1, unsigned long v2, unsigned long *r) -{ return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r)); } -# endif -#endif -#if defined(Q_CC_MSVC) && (defined(Q_PROCESSOR_X86_64) || defined(Q_PROCESSOR_IA64)) && !QT_HAS_BUILTIN(__builtin_uadd_overflow) -#pragma intrinsic(_umul128) +# pragma intrinsic(_umul128) template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r) { // use 128-bit multiplication with the _umul128 intrinsic @@ -247,117 +291,30 @@ template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r) *r = _umul128(v1, v2, &high); return high; } -# define HAVE_MUL64_OVERFLOW -#endif - -#if !defined(HAVE_MUL64_OVERFLOW) && defined(__LP64__) -// no 128-bit multiplication, we need to figure out with a slow division -template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r) -{ - if (v2 && v1 > std::numeric_limits<quint64>::max() / v2) - return true; - *r = v1 * v2; - return false; -} -template <> inline bool mul_overflow(unsigned long v1, unsigned long v2, unsigned long *r) -{ - return mul_overflow<quint64>(v1, v2, reinterpret_cast<quint64 *>(r)); -} -#else -# undef HAVE_MUL64_OVERFLOW -#endif - -// -// Signed overflow math -// -// In C++, signed overflow math is Undefined Behavior. However, many CPUs do implement some way to -// check for overflow. Some compilers expose intrinsics to use this functionality. If the no -// intrinsic is exposed, overflow checking can be done by widening the result type and "manually" -// checking for overflow. Or, alternatively, by using inline assembly to use the CPU features. -// -// Only int overflow checking is implemented, because it's the only one used. -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_sadd_overflow) -inline bool add_overflow(int v1, int v2, int *r) -{ return __builtin_sadd_overflow(v1, v2, r); } -#elif defined(Q_CC_GNU) && defined(Q_PROCESSOR_X86) -inline bool add_overflow(int v1, int v2, int *r) -{ - quint8 overflow = 0; - int res = v1; - - asm ("addl %2, %1\n" - "seto %0" - : "=q" (overflow), "=r" (res) - : "r" (v2), "1" (res) - : "cc" - ); - *r = res; - return overflow; -} -#else -inline bool add_overflow(int v1, int v2, int *r) -{ - qint64 t = qint64(v1) + v2; - *r = static_cast<int>(t); - return t > std::numeric_limits<int>::max() || t < std::numeric_limits<int>::min(); -} -#endif -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_ssub_overflow) -inline bool sub_overflow(int v1, int v2, int *r) -{ return __builtin_ssub_overflow(v1, v2, r); } -#elif defined(Q_CC_GNU) && defined(Q_PROCESSOR_X86) -inline bool sub_overflow(int v1, int v2, int *r) +# pragma intrinsic(_mul128) +template <> inline bool mul_overflow(qint64 v1, qint64 v2, qint64 *r) { - quint8 overflow = 0; - int res = v1; - - asm ("subl %2, %1\n" - "seto %0" - : "=q" (overflow), "=r" (res) - : "r" (v2), "1" (res) - : "cc" - ); - *r = res; - return overflow; + // Use 128-bit multiplication with the _mul128 intrinsic + // https://msdn.microsoft.com/en-us/library/82cxdw50.aspx + + // This is slightly more complex than the unsigned case above: the sign bit + // of 'low' must be replicated as the entire 'high', so the only valid + // values for 'high' are 0 and -1. + + qint64 high; + *r = _mul128(v1, v2, &high); + if (high == 0) + return *r < 0; + if (high == -1) + return *r >= 0; + return true; } -#else -inline bool sub_overflow(int v1, int v2, int *r) -{ - qint64 t = qint64(v1) - v2; - *r = static_cast<int>(t); - return t > std::numeric_limits<int>::max() || t < std::numeric_limits<int>::min(); +# endif // x86-64 +# endif // MSVC x86 +#endif // !GCC } -#endif - -#if (defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 500) || QT_HAS_BUILTIN(__builtin_smul_overflow) -inline bool mul_overflow(int v1, int v2, int *r) -{ return __builtin_smul_overflow(v1, v2, r); } -#elif defined(Q_CC_GNU) && defined(Q_PROCESSOR_X86) -inline bool mul_overflow(int v1, int v2, int *r) -{ - quint8 overflow = 0; - int res = v1; - - asm ("imul %2, %1\n" - "seto %0" - : "=q" (overflow), "=r" (res) - : "r" (v2), "1" (res) - : "cc" - ); - *r = res; - return overflow; -} -#else -inline bool mul_overflow(int v1, int v2, int *r) -{ - qint64 t = qint64(v1) * v2; - *r = static_cast<int>(t); - return t > std::numeric_limits<int>::max() || t < std::numeric_limits<int>::min(); -} -#endif #endif // Q_CLANG_QDOC -} QT_END_NAMESPACE diff --git a/src/corelib/global/qtrace_p.h b/src/corelib/global/qtrace_p.h new file mode 100644 index 0000000000..ab8fc14af5 --- /dev/null +++ b/src/corelib/global/qtrace_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** 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$ +** +****************************************************************************/ + +#ifndef QTRACE_P_H +#define QTRACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +/* + * The Qt tracepoints API consists of only three macros: + * + * - Q_TRACE(tracepoint, args...) + * Fires 'tracepoint' if it is enabled. + * + * - Q_UNCONDITIONAL_TRACE(tracepoint, args...) + * Fires 'tracepoint' unconditionally: no check is performed to query + * whether 'tracepoint' is enabled. + * + * - Q_TRACE_ENABLED(tracepoint) + * Returns 'true' if 'tracepoint' is enabled; false otherwise. + * + * When using LTTNG, Q_TRACE, Q_UNCONDITIONAL_TRACE and Q_TRACE_ENABLED map + * ultimately to tracepoint(), do_tracepoint() and tracepoint_enabled(), + * respectively, described on the lttng-ust manpage (man 3 lttng-ust). + * + * On ETW, Q_TRACE() and Q_UNCONDITIONAL_TRACE() are equivalent, ultimately + * amounting to a call to TraceLoggingWrite(), whereas Q_TRACE_ENABLED() + * wraps around TraceLoggingProviderEnabled(). + * + * A tracepoint provider is defined in a separate file, that follows the + * following format: + * + * tracepoint_name(arg_type arg_name, ...) + * + * For instance: + * + * qcoreapplication_ctor(int argc, const char * const argv) + * qcoreapplication_foo(int argc, const char[10] argv) + * qcoreapplication_baz(const char[len] some_string, unsigned int len) + * qcoreapplication_qstring(const QString &foo) + * qcoreapplication_qrect(const QRect &rect) + * + * The provider file is then parsed by src/tools/tracegen, which can be + * switched to output either ETW or LTTNG tracepoint definitions. The provider + * name is deduced to be basename(provider_file). + * + * To use the above (inside qtcore), you need to include + * <providername_tracepoints_p.h>. After that, the following call becomes + * possible: + * + * Q_TRACE(qcoreapplication_qrect, myRect); + * + * Currently, all C++ primitive non-pointer types are supported for + * arguments. Additionally, char * is supported, and is assumed to + * be a NULL-terminated string. Finally, the following subset of Qt types also + * currently supported: + * + * - QString + * - QByteArray + * - QUrl + * - QRect + * + * Dynamic arrays are supported using the syntax illustrated by + * qcoreapplication_baz above. + */ + +QT_BEGIN_NAMESPACE + +#if defined(Q_TRACEPOINT) && !defined(QT_BOOTSTRAPPED) +# define Q_TRACE(x, ...) QtPrivate::trace_ ## x(__VA_ARGS__) +# define Q_UNCONDITIONAL_TRACE(x, ...) QtPrivate::do_trace_ ## x(__VA_ARGS__) +# define Q_TRACE_ENABLED(x) QtPrivate::trace_ ## x ## _enabled() +#else +# define Q_TRACE(x, ...) +# define Q_UNCONDITIONAL_TRACE(x, ...) +# define Q_TRACE_ENABLED(x) false +#endif // defined(Q_TRACEPOINT) && !defined(QT_BOOTSTRAPPED) + +QT_END_NAMESPACE + +#endif // QTRACE_P_H diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 4614fe2a6b..c6a5973306 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -3,8 +3,6 @@ HEADERS += \ io/qabstractfileengine_p.h \ io/qbuffer.h \ - io/qdatastream.h \ - io/qdatastream_p.h \ io/qdataurl_p.h \ io/qdebug.h \ io/qdebug_p.h \ @@ -22,8 +20,6 @@ HEADERS += \ io/qlockfile.h \ io/qlockfile_p.h \ io/qnoncontiguousbytedevice_p.h \ - io/qtextstream.h \ - io/qtextstream_p.h \ io/qtemporarydir.h \ io/qtemporaryfile.h \ io/qtemporaryfile_p.h \ @@ -57,7 +53,6 @@ HEADERS += \ SOURCES += \ io/qabstractfileengine.cpp \ io/qbuffer.cpp \ - io/qdatastream.cpp \ io/qdataurl.cpp \ io/qtldurl.cpp \ io/qdebug.cpp \ @@ -71,7 +66,6 @@ SOURCES += \ io/qlockfile.cpp \ io/qnoncontiguousbytedevice.cpp \ io/qstorageinfo.cpp \ - io/qtextstream.cpp \ io/qtemporarydir.cpp \ io/qtemporaryfile.cpp \ io/qresource.cpp \ diff --git a/src/corelib/json/json.pri b/src/corelib/json/json.pri deleted file mode 100644 index 1a4e2a72bf..0000000000 --- a/src/corelib/json/json.pri +++ /dev/null @@ -1,17 +0,0 @@ -HEADERS += \ - json/qjson_p.h \ - json/qjsondocument.h \ - json/qjsonobject.h \ - json/qjsonvalue.h \ - json/qjsonarray.h \ - json/qjsonwriter_p.h \ - json/qjsonparser_p.h - -SOURCES += \ - json/qjson.cpp \ - json/qjsondocument.cpp \ - json/qjsonobject.cpp \ - json/qjsonarray.cpp \ - json/qjsonvalue.cpp \ - json/qjsonwriter.cpp \ - json/qjsonparser.cpp diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index e93a14c116..4bab0b9f01 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -116,6 +116,12 @@ # include <taskLib.h> #endif +#ifdef QT_BOOTSTRAPPED +#include <private/qtrace_p.h> +#else +#include <qtcore_tracepoints_p.h> +#endif + #include <algorithm> QT_BEGIN_NAMESPACE @@ -790,6 +796,8 @@ QCoreApplication::QCoreApplication(int &argc, char **argv void QCoreApplicationPrivate::init() { + Q_TRACE(qcoreapplicationprivate_init_entry); + #if defined(Q_OS_MACOS) QMacAutoReleasePool pool; #endif @@ -873,6 +881,8 @@ void QCoreApplicationPrivate::init() #ifndef QT_NO_QOBJECT is_app_running = true; // No longer starting up. #endif + + Q_TRACE(qcoreapplicationprivate_init_exit); } /*! diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm index 608dea5426..8499b3fd57 100644 --- a/src/corelib/kernel/qeventdispatcher_cf.mm +++ b/src/corelib/kernel/qeventdispatcher_cf.mm @@ -112,14 +112,15 @@ static CFStringRef runLoopMode(NSDictionary *dictionary) if (CFStringRef mode = runLoopMode(notification.userInfo)) m_runLoopModes.push(mode); else - qWarning("Encountered run loop push notification without run loop mode!"); + qCWarning(lcEventDispatcher) << "Encountered run loop push notification without run loop mode!"; } else if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePopNotification"))) { CFStringRef mode = runLoopMode(notification.userInfo); if (CFStringCompare(mode, [self currentMode], 0) == kCFCompareEqualTo) m_runLoopModes.pop(); else - qWarning("Tried to pop run loop mode '%s' that was never pushed!", qPrintable(QString::fromCFString(mode))); + qCWarning(lcEventDispatcher) << "Tried to pop run loop mode" + << qPrintable(QString::fromCFString(mode)) << "that was never pushed!"; Q_ASSERT(m_runLoopModes.size() >= 1); } @@ -134,6 +135,9 @@ static CFStringRef runLoopMode(NSDictionary *dictionary) QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher"); +Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers"); + class RunLoopDebugger : public QObject { Q_OBJECT @@ -177,10 +181,6 @@ QDebug operator<<(QDebug s, timespec tv) return s; } -#if DEBUG_EVENT_DISPATCHER -uint g_eventDispatcherIndentationLevel = 0; -#endif - static const CFTimeInterval kCFTimeIntervalMinimum = 0; static const CFTimeInterval kCFTimeIntervalDistantFuture = std::numeric_limits<CFTimeInterval>::max(); @@ -190,13 +190,7 @@ QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent) : QAbstractEventDispatcher(parent) , m_processEvents(QEventLoop::EventLoopExec) , m_postedEventsRunLoopSource(this, &QEventDispatcherCoreFoundation::processPostedEvents) - , m_runLoopActivityObserver(this, &QEventDispatcherCoreFoundation::handleRunLoopActivity, -#if DEBUG_EVENT_DISPATCHER - kCFRunLoopAllActivities -#else - kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting -#endif - ) + , m_runLoopActivityObserver(this, &QEventDispatcherCoreFoundation::handleRunLoopActivity, kCFRunLoopAllActivities) , m_runLoopModeTracker([[RunLoopModeTracker alloc] init]) , m_runLoopTimer(0) , m_blockedRunLoopTimer(0) @@ -247,14 +241,14 @@ bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlag bool eventsProcessed = false; if (flags & (QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers)) - qWarning() << "processEvents() flags" << flags << "not supported on iOS"; + qCWarning(lcEventDispatcher) << "processEvents() flags" << flags << "not supported on iOS"; - qEventDispatcherDebug() << "Entering with " << flags; qIndent(); + qCDebug(lcEventDispatcher) << "Processing events with flags" << flags; if (m_blockedRunLoopTimer) { Q_ASSERT(m_blockedRunLoopTimer == m_runLoopTimer); - qEventDispatcherDebug() << "Recursing from blocked timer " << m_blockedRunLoopTimer; + qCDebug(lcEventDispatcher) << "Recursing from blocked timer" << m_blockedRunLoopTimer; m_runLoopTimer = 0; // Unset current timer to force creation of new timer updateTimers(); } @@ -266,7 +260,7 @@ bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlag m_postedEventsRunLoopSource.signal(); m_processEvents.deferredWakeUp = false; - qEventDispatcherDebug() << "Processed deferred wake-up"; + qCDebug(lcEventDispatcher) << "Processed deferred wake-up"; } // The documentation states that this signal is emitted after the event @@ -287,12 +281,12 @@ bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlag CFTimeInterval duration = (m_processEvents.flags & QEventLoop::WaitForMoreEvents) ? kCFTimeIntervalDistantFuture : kCFTimeIntervalMinimum; - qEventDispatcherDebug() << "Calling CFRunLoopRunInMode = " << qPrintable(QString::fromCFString(mode)) - << " for " << duration << " ms, processing single source = " << returnAfterSingleSourceHandled; qIndent(); + qCDebug(lcEventDispatcher) << "Calling CFRunLoopRunInMode =" << qPrintable(QString::fromCFString(mode)) + << "for" << duration << "ms, processing single source =" << returnAfterSingleSourceHandled; SInt32 result = CFRunLoopRunInMode(mode, duration, returnAfterSingleSourceHandled); - qUnIndent(); qEventDispatcherDebug() << "result = " << qPrintableResult(result); + qCDebug(lcEventDispatcher) << "result =" << qPrintableResult(result); eventsProcessed |= (result == kCFRunLoopRunHandledSource || m_processEvents.processedPostedEvents @@ -316,15 +310,15 @@ bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlag // immediately, since it has already been exited. if (!currentEventLoop()->isRunning()) { - qEventDispatcherDebug() << "Top level event loop was exited"; + qCDebug(lcEventDispatcher) << "Top level event loop was exited"; break; } else { - qEventDispatcherDebug() << "Top level event loop still running, making another pass"; + qCDebug(lcEventDispatcher) << "Top level event loop still running, making another pass"; } } else { // We were called manually, through processEvents(), and should stop processing // events, even if we didn't finish processing all the queued events. - qEventDispatcherDebug() << "Top level processEvents was interrupted"; + qCDebug(lcEventDispatcher) << "Top level processEvents was interrupted"; break; } } @@ -353,7 +347,7 @@ bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlag // date in the past (overdue) will fire on the next run loop pass. The Qt // APIs on the other hand document eg. zero-interval timers to always be // handled after processing all available window-system events. - qEventDispatcherDebug() << "Manually processing timers due to overdue timer"; + qCDebug(lcEventDispatcher) << "Manually processing timers due to overdue timer"; processTimers(0); eventsProcessed = true; } @@ -372,7 +366,7 @@ bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlag if (m_processEvents.deferredWakeUp) { m_postedEventsRunLoopSource.signal(); - qEventDispatcherDebug() << "Processed deferred wake-up"; + qCDebug(lcEventDispatcher) << "Processed deferred wake-up"; } bool wasInterrupted = m_processEvents.wasInterrupted; @@ -385,11 +379,11 @@ bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlag // others below it (eg, in the case of nested event loops). We need to trigger // another interrupt so that the parent processEvents call has a chance to check // if it should continue. - qEventDispatcherDebug() << "Forwarding interrupt in case of nested processEvents"; + qCDebug(lcEventDispatcher) << "Forwarding interrupt in case of nested processEvents"; interrupt(); } - qEventDispatcherDebug() << "Returning with eventsProcessed = " << eventsProcessed; qUnIndent(); + qCDebug(lcEventDispatcher) << "Returning with eventsProcessed =" << eventsProcessed; return eventsProcessed; } @@ -397,15 +391,14 @@ bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlag bool QEventDispatcherCoreFoundation::processPostedEvents() { if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) { - qEventDispatcherDebug() << "Already processed events this pass"; + qCDebug(lcEventDispatcher) << "Already processed events this pass"; return false; } m_processEvents.processedPostedEvents = true; - qEventDispatcherDebug() << "Sending posted events for " << m_processEvents.flags; qIndent(); + qCDebug(lcEventDispatcher) << "Sending posted events for" << m_processEvents.flags; QCoreApplication::sendPostedEvents(); - qUnIndent(); return true; } @@ -413,12 +406,12 @@ bool QEventDispatcherCoreFoundation::processPostedEvents() void QEventDispatcherCoreFoundation::processTimers(CFRunLoopTimerRef timer) { if (m_processEvents.processedTimers && !(m_processEvents.flags & QEventLoop::EventLoopExec)) { - qEventDispatcherDebug() << "Already processed timers this pass"; + qCDebug(lcEventDispatcher) << "Already processed timers this pass"; m_processEvents.deferredUpdateTimers = true; return; } - qEventDispatcherDebug() << "CFRunLoopTimer " << timer << " fired, activating Qt timers"; qIndent(); + qCDebug(lcEventDispatcher) << "CFRunLoopTimer" << timer << "fired, activating Qt timers"; // Activating Qt timers might recurse into processEvents() if a timer-callback // brings up a new event-loop or tries to processes events manually. Although @@ -436,15 +429,15 @@ void QEventDispatcherCoreFoundation::processTimers(CFRunLoopTimerRef timer) m_blockedRunLoopTimer = previouslyBlockedRunLoopTimer; m_processEvents.processedTimers = true; - qUnIndent(); - // Now that the timer source is unblocked we may need to schedule it again updateTimers(); } +Q_LOGGING_CATEGORY(lcEventDispatcherActivity, "qt.eventdispatcher.activity") + void QEventDispatcherCoreFoundation::handleRunLoopActivity(CFRunLoopActivity activity) { - qEventDispatcherDebug() << qPrintableActivity(activity); + qCDebug(lcEventDispatcherActivity) << "Runloop entered activity" << qPrintableActivity(activity); switch (activity) { case kCFRunLoopBeforeWaiting: @@ -463,13 +456,11 @@ void QEventDispatcherCoreFoundation::handleRunLoopActivity(CFRunLoopActivity act case kCFRunLoopAfterWaiting: emit awake(); break; -#if DEBUG_EVENT_DISPATCHER case kCFRunLoopEntry: case kCFRunLoopBeforeTimers: case kCFRunLoopBeforeSources: case kCFRunLoopExit: break; -#endif default: Q_UNREACHABLE(); } @@ -502,19 +493,19 @@ void QEventDispatcherCoreFoundation::wakeUp() // posted event gets processed on the next processEvents() call, so we flag the // need to do a deferred wake-up. m_processEvents.deferredWakeUp = true; - qEventDispatcherDebug() << "Already processed posted events, deferring wakeUp"; + qCDebug(lcEventDispatcher) << "Already processed posted events, deferring wakeUp"; return; } m_postedEventsRunLoopSource.signal(); CFRunLoopWakeUp(CFRunLoopGetMain()); - qEventDispatcherDebug() << "Signaled posted event run-loop source"; + qCDebug(lcEventDispatcher) << "Signaled posted event run-loop source"; } void QEventDispatcherCoreFoundation::interrupt() { - qEventDispatcherDebug() << "Marking current processEvent as interrupted"; + qCDebug(lcEventDispatcher) << "Marking current processEvent as interrupted"; m_processEvents.wasInterrupted = true; CFRunLoopStop(CFRunLoopGetMain()); } @@ -540,8 +531,8 @@ void QEventDispatcherCoreFoundation::unregisterSocketNotifier(QSocketNotifier *n void QEventDispatcherCoreFoundation::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object) { - qEventDispatcherDebug() << "id = " << timerId << ", interval = " << interval - << ", type = " << timerType << ", object = " << object; + qCDebug(lcEventDispatcherTimers) << "Registering timer with id =" << timerId << "interval =" << interval + << "type =" << timerType << "object =" << object; Q_ASSERT(timerId > 0 && interval >= 0 && object); Q_ASSERT(object->thread() == thread() && thread() == QThread::currentThread()); @@ -557,7 +548,7 @@ bool QEventDispatcherCoreFoundation::unregisterTimer(int timerId) bool returnValue = m_timerInfoList.unregisterTimer(timerId); - qEventDispatcherDebug() << "id = " << timerId << ", timers left: " << m_timerInfoList.size(); + qCDebug(lcEventDispatcherTimers) << "Unegistered timer with id =" << timerId << "Timers left:" << m_timerInfoList.size(); updateTimers(); return returnValue; @@ -569,7 +560,7 @@ bool QEventDispatcherCoreFoundation::unregisterTimers(QObject *object) bool returnValue = m_timerInfoList.unregisterTimers(object); - qEventDispatcherDebug() << "object = " << object << ", timers left: " << m_timerInfoList.size(); + qCDebug(lcEventDispatcherTimers) << "Unegistered timers for object =" << object << "Timers left:" << m_timerInfoList.size(); updateTimers(); return returnValue; @@ -612,16 +603,16 @@ void QEventDispatcherCoreFoundation::updateTimers() }); CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimer, kCFRunLoopCommonModes); - qEventDispatcherDebug() << "Created new CFRunLoopTimer " << m_runLoopTimer; + qCDebug(lcEventDispatcherTimers) << "Created new CFRunLoopTimer" << m_runLoopTimer; } else { CFRunLoopTimerSetNextFireDate(m_runLoopTimer, timeToFire); - qEventDispatcherDebug() << "Re-scheduled CFRunLoopTimer " << m_runLoopTimer; + qCDebug(lcEventDispatcherTimers) << "Re-scheduled CFRunLoopTimer" << m_runLoopTimer; } m_overdueTimerScheduled = !timespecToSeconds(tv); - qEventDispatcherDebug() << "Next timeout in " << tv << " seconds"; + qCDebug(lcEventDispatcherTimers) << "Next timeout in" << tv << "seconds"; } else { // No Qt timers are registered, so make sure we're not running any CF timers @@ -637,7 +628,7 @@ void QEventDispatcherCoreFoundation::invalidateTimer() return; CFRunLoopTimerInvalidate(m_runLoopTimer); - qEventDispatcherDebug() << "Invalidated CFRunLoopTimer " << m_runLoopTimer; + qCDebug(lcEventDispatcherTimers) << "Invalidated CFRunLoopTimer" << m_runLoopTimer; CFRelease(m_runLoopTimer); m_runLoopTimer = 0; diff --git a/src/corelib/kernel/qeventdispatcher_cf_p.h b/src/corelib/kernel/qeventdispatcher_cf_p.h index 8a234ebc40..a607ab7a15 100644 --- a/src/corelib/kernel/qeventdispatcher_cf_p.h +++ b/src/corelib/kernel/qeventdispatcher_cf_p.h @@ -85,19 +85,22 @@ // We mean it. // -#define DEBUG_EVENT_DISPATCHER 0 - #include <QtCore/qabstracteventdispatcher.h> #include <QtCore/private/qtimerinfo_unix_p.h> #include <QtCore/private/qcfsocketnotifier_p.h> #include <QtCore/private/qcore_mac_p.h> #include <QtCore/qdebug.h> +#include <QtCore/qloggingcategory.h> + #include <CoreFoundation/CoreFoundation.h> Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(RunLoopModeTracker)); QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher); +Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcherTimers) + class QEventDispatcherCoreFoundation; template <class T = QEventDispatcherCoreFoundation> @@ -269,17 +272,4 @@ private: QT_END_NAMESPACE -#if DEBUG_EVENT_DISPATCHER -extern uint g_eventDispatcherIndentationLevel; -#define qEventDispatcherDebug() qDebug().nospace() \ - << qPrintable(QString(QLatin1String("| ")).repeated(g_eventDispatcherIndentationLevel)) \ - << __FUNCTION__ << "(): " -#define qIndent() ++g_eventDispatcherIndentationLevel -#define qUnIndent() --g_eventDispatcherIndentationLevel -#else -#define qEventDispatcherDebug() QT_NO_QDEBUG_MACRO() -#define qIndent() -#define qUnIndent() -#endif - #endif // QEVENTDISPATCHER_CF_P_H diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 6fcc6b8d30..7ccacd883f 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -3892,6 +3892,19 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p) \sa setValue(), value() */ +/*! \fn static inline QVariant fromStdVariant(const std::variant<T, Types...> &value) + \since 5.11 + + Returns a QVariant with the type and value of the active variant of \a value. If + the active type is std::monostate a default QVariant is returned. + + \note With this method you do not need to register the variant as a Qt metatype, + since the std::variant is resolved before being stored. The component types + should be registered however. + + \sa fromValue() +*/ + /*! \fn template<typename T> QVariant qVariantFromValue(const T &value) \relates QVariant diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 29e67e9dd8..fe1ef1bdfc 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -53,6 +53,10 @@ #include <QtCore/qbytearraylist.h> #endif +#if QT_HAS_INCLUDE(<variant>) && __cplusplus >= 201703L +#include <variant> +#endif + QT_BEGIN_NAMESPACE @@ -355,6 +359,16 @@ class Q_CORE_EXPORT QVariant static inline QVariant fromValue(const T &value) { return qVariantFromValue(value); } +#if QT_HAS_INCLUDE(<variant>) && __cplusplus >= 201703L + template<typename... Types> + static inline QVariant fromStdVariant(const std::variant<Types...> &value) + { + if (value.valueless_by_exception()) + return QVariant(); + return std::visit([](const auto &arg) { return fromValue(arg); }, value); + } +#endif + template<typename T> bool canConvert() const { return canConvert(qMetaTypeId<T>()); } @@ -503,6 +517,11 @@ inline QVariant qVariantFromValue(const T &t) template <> inline QVariant qVariantFromValue(const QVariant &t) { return t; } +#if QT_HAS_INCLUDE(<variant>) && __cplusplus >= 201703L +template <> +inline QVariant qVariantFromValue(const std::monostate &) { return QVariant(); } +#endif + template <typename T> inline void qVariantSetValue(QVariant &v, const T &t) { diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index 8f6237c1cb..d7590ecf1f 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -466,6 +466,8 @@ QStringList QMimeType::suffixes() const */ QString QMimeType::preferredSuffix() const { + if (isDefault()) // workaround for unwanted *.bin suffix for octet-stream, https://bugs.freedesktop.org/show_bug.cgi?id=101667, fixed upstream in 1.10 + return QString(); const QStringList suffixList = suffixes(); return suffixList.isEmpty() ? QString() : suffixList.at(0); } diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 0cc193c325..a4be18a67f 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -54,6 +54,8 @@ #include "qjsonobject.h" #include "qjsonarray.h" +#include <qtcore_tracepoints_p.h> + QT_BEGIN_NAMESPACE class QFactoryLoaderPrivate : public QObjectPrivate @@ -142,6 +144,9 @@ void QFactoryLoader::update() if (qt_debug_component()) { qDebug() << "QFactoryLoader::QFactoryLoader() looking at" << fileName; } + + Q_TRACE(qfactoryloader_update, fileName); + library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath()); if (!library->isPlugin()) { if (qt_debug_component()) { diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index ebad7f1751..bca6918b4a 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -64,6 +64,8 @@ #include "qelfparser_p.h" #include "qmachparser_p.h" +#include <qtcore_tracepoints_p.h> + QT_BEGIN_NAMESPACE #ifdef QT_NO_DEBUG @@ -535,6 +537,8 @@ bool QLibraryPrivate::load() if (fileName.isEmpty()) return false; + Q_TRACE(qlibraryprivate_load_entry, fileName); + bool ret = load_sys(); if (qt_debug_component()) { if (ret) { @@ -551,6 +555,8 @@ bool QLibraryPrivate::load() installCoverageTool(this); } + Q_TRACE(qlibraryprivate_load_exit, ret); + return ret; } diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp index 4d658e064c..b113ca13ce 100644 --- a/src/corelib/plugin/quuid.cpp +++ b/src/corelib/plugin/quuid.cpp @@ -149,7 +149,6 @@ static QUuid _q_uuidFromHex(const char *src) return QUuid(); } -#ifndef QT_BOOTSTRAPPED static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCryptographicHash::Algorithm algorithm, int version) { QByteArray hashResult; @@ -172,7 +171,6 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto return result; } -#endif /*! \class QUuid @@ -510,12 +508,12 @@ QUuid QUuid::createUuidV3(const QUuid &ns, const QByteArray &baseData) { return createFromName(ns, baseData, QCryptographicHash::Md5, 3); } +#endif QUuid QUuid::createUuidV5(const QUuid &ns, const QByteArray &baseData) { return createFromName(ns, baseData, QCryptographicHash::Sha1, 5); } -#endif /*! Creates a QUuid object from the binary representation of the UUID, as diff --git a/src/corelib/plugin/quuid.h b/src/corelib/plugin/quuid.h index 27a84b4e01..08a1843640 100644 --- a/src/corelib/plugin/quuid.h +++ b/src/corelib/plugin/quuid.h @@ -201,18 +201,20 @@ public: static QUuid createUuid(); #ifndef QT_BOOTSTRAPPED static QUuid createUuidV3(const QUuid &ns, const QByteArray &baseData); +#endif static QUuid createUuidV5(const QUuid &ns, const QByteArray &baseData); +#ifndef QT_BOOTSTRAPPED static inline QUuid createUuidV3(const QUuid &ns, const QString &baseData) { return QUuid::createUuidV3(ns, baseData.toUtf8()); } +#endif static inline QUuid createUuidV5(const QUuid &ns, const QString &baseData) { return QUuid::createUuidV5(ns, baseData.toUtf8()); } -#endif QUuid::Variant variant() const Q_DECL_NOTHROW; QUuid::Version version() const Q_DECL_NOTHROW; diff --git a/src/corelib/qtcore.tracepoints b/src/corelib/qtcore.tracepoints new file mode 100644 index 0000000000..e6b666ac74 --- /dev/null +++ b/src/corelib/qtcore.tracepoints @@ -0,0 +1,5 @@ +qcoreapplicationprivate_init_entry() +qcoreapplicationprivate_init_exit() +qfactoryloader_update(const QString &fileName) +qlibraryprivate_load_entry(const QString &fileName) +qlibraryprivate_load_exit(bool success) diff --git a/src/corelib/xml/.gitignore b/src/corelib/serialization/.gitignore index 89f9ac04aa..89f9ac04aa 100644 --- a/src/corelib/xml/.gitignore +++ b/src/corelib/serialization/.gitignore diff --git a/src/corelib/xml/make-parser.sh b/src/corelib/serialization/make-xml-parser.sh index 0296e4c22b..0296e4c22b 100755 --- a/src/corelib/xml/make-parser.sh +++ b/src/corelib/serialization/make-xml-parser.sh diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp index 8f419a4a46..8f419a4a46 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/serialization/qdatastream.cpp diff --git a/src/corelib/io/qdatastream.h b/src/corelib/serialization/qdatastream.h index 1f1b13686c..1f1b13686c 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h diff --git a/src/corelib/io/qdatastream_p.h b/src/corelib/serialization/qdatastream_p.h index 3ca0ae840e..3ca0ae840e 100644 --- a/src/corelib/io/qdatastream_p.h +++ b/src/corelib/serialization/qdatastream_p.h diff --git a/src/corelib/json/qjson.cpp b/src/corelib/serialization/qjson.cpp index e4bca3bcd0..e4bca3bcd0 100644 --- a/src/corelib/json/qjson.cpp +++ b/src/corelib/serialization/qjson.cpp diff --git a/src/corelib/json/qjson_p.h b/src/corelib/serialization/qjson_p.h index 131528376b..7743382806 100644 --- a/src/corelib/json/qjson_p.h +++ b/src/corelib/serialization/qjson_p.h @@ -154,14 +154,7 @@ static inline bool useCompressed(const QString &s) { if (s.length() >= 0x8000) return false; - const ushort *uc = (const ushort *)s.constData(); - const ushort *e = uc + s.length(); - while (uc < e) { - if (*uc > 0xff) - return false; - ++uc; - } - return true; + return QtPrivate::isLatin1(s); } static inline int qStringSize(const QString &string, bool compress) diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/serialization/qjsonarray.cpp index c5a5aaf39d..c5a5aaf39d 100644 --- a/src/corelib/json/qjsonarray.cpp +++ b/src/corelib/serialization/qjsonarray.cpp diff --git a/src/corelib/json/qjsonarray.h b/src/corelib/serialization/qjsonarray.h index 8d41138c97..8d41138c97 100644 --- a/src/corelib/json/qjsonarray.h +++ b/src/corelib/serialization/qjsonarray.h diff --git a/src/corelib/json/qjsondocument.cpp b/src/corelib/serialization/qjsondocument.cpp index 9794bca60d..9794bca60d 100644 --- a/src/corelib/json/qjsondocument.cpp +++ b/src/corelib/serialization/qjsondocument.cpp diff --git a/src/corelib/json/qjsondocument.h b/src/corelib/serialization/qjsondocument.h index b784890c54..b784890c54 100644 --- a/src/corelib/json/qjsondocument.h +++ b/src/corelib/serialization/qjsondocument.h diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/serialization/qjsonobject.cpp index 4a316c8a6f..4a316c8a6f 100644 --- a/src/corelib/json/qjsonobject.cpp +++ b/src/corelib/serialization/qjsonobject.cpp diff --git a/src/corelib/json/qjsonobject.h b/src/corelib/serialization/qjsonobject.h index 610bce694c..610bce694c 100644 --- a/src/corelib/json/qjsonobject.h +++ b/src/corelib/serialization/qjsonobject.h diff --git a/src/corelib/json/qjsonparser.cpp b/src/corelib/serialization/qjsonparser.cpp index 39738b90a8..39738b90a8 100644 --- a/src/corelib/json/qjsonparser.cpp +++ b/src/corelib/serialization/qjsonparser.cpp diff --git a/src/corelib/json/qjsonparser_p.h b/src/corelib/serialization/qjsonparser_p.h index 379256847f..379256847f 100644 --- a/src/corelib/json/qjsonparser_p.h +++ b/src/corelib/serialization/qjsonparser_p.h diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp index 33707b6ec3..33707b6ec3 100644 --- a/src/corelib/json/qjsonvalue.cpp +++ b/src/corelib/serialization/qjsonvalue.cpp diff --git a/src/corelib/json/qjsonvalue.h b/src/corelib/serialization/qjsonvalue.h index 96538ebbf9..96538ebbf9 100644 --- a/src/corelib/json/qjsonvalue.h +++ b/src/corelib/serialization/qjsonvalue.h diff --git a/src/corelib/json/qjsonwriter.cpp b/src/corelib/serialization/qjsonwriter.cpp index 12ce20ef09..12ce20ef09 100644 --- a/src/corelib/json/qjsonwriter.cpp +++ b/src/corelib/serialization/qjsonwriter.cpp diff --git a/src/corelib/json/qjsonwriter_p.h b/src/corelib/serialization/qjsonwriter_p.h index 76a8460449..76a8460449 100644 --- a/src/corelib/json/qjsonwriter_p.h +++ b/src/corelib/serialization/qjsonwriter_p.h diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/serialization/qtextstream.cpp index ee3cb4efcb..ee3cb4efcb 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/serialization/qtextstream.cpp diff --git a/src/corelib/io/qtextstream.h b/src/corelib/serialization/qtextstream.h index ee0b09419d..ee0b09419d 100644 --- a/src/corelib/io/qtextstream.h +++ b/src/corelib/serialization/qtextstream.h diff --git a/src/corelib/io/qtextstream_p.h b/src/corelib/serialization/qtextstream_p.h index a642beddc4..a642beddc4 100644 --- a/src/corelib/io/qtextstream_p.h +++ b/src/corelib/serialization/qtextstream_p.h diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index 9b5295a17e..a92dd71df5 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -409,6 +409,11 @@ QXmlStreamReader::QXmlStreamReader(const QByteArray &data) /*! Creates a new stream reader that reads from \a data. + This function should only be used if the XML header either says the encoding + is "UTF-8" or lacks any encoding information (the latter is the case of + QXmlStreamWriter writing to a QString). Any other encoding is likely going to + cause data corruption ("mojibake"). + \sa addData(), clear(), setDevice() */ QXmlStreamReader::QXmlStreamReader(const QString &data) @@ -3268,6 +3273,9 @@ QXmlStreamWriter::QXmlStreamWriter(QByteArray *array) /*! Constructs a stream writer that writes into \a string. + * + * Note that when writing to QString, QXmlStreamWriter ignores the codec set + * with setCodec(). See that function for more information. */ QXmlStreamWriter::QXmlStreamWriter(QString *string) : d_ptr(new QXmlStreamWriterPrivate(this)) @@ -3326,6 +3334,12 @@ QIODevice *QXmlStreamWriter::device() const gets written when you call writeStartDocument(). Call this function before calling writeStartDocument(). + \note When writing the XML to a QString, the codec information is ignored + and the XML header will not include any encoding information, since all + QStrings are UTF-16. If you later convert the QString to an 8-bit format, + you must arrange for the encoding information to be transmitted + out-of-band. + \sa codec() */ void QXmlStreamWriter::setCodec(QTextCodec *codec) @@ -3345,6 +3359,12 @@ void QXmlStreamWriter::setCodec(QTextCodec *codec) "ISO 8859-1", "UTF-8", and "UTF-16". If the encoding isn't recognized, nothing happens. + \note When writing the XML to a QString, the codec information is ignored + and the XML header will not include any encoding information, since all + QStrings are UTF-16. If you later convert the QString to an 8-bit format, + you must arrange for the encoding information to be transmitted + out-of-band. + \sa QTextCodec::codecForName() */ void QXmlStreamWriter::setCodec(const char *codecName) diff --git a/src/corelib/xml/qxmlstream.g b/src/corelib/serialization/qxmlstream.g index fd69a6e4af..fd69a6e4af 100644 --- a/src/corelib/xml/qxmlstream.g +++ b/src/corelib/serialization/qxmlstream.g diff --git a/src/corelib/xml/qxmlstream.h b/src/corelib/serialization/qxmlstream.h index 2350d12dd6..2350d12dd6 100644 --- a/src/corelib/xml/qxmlstream.h +++ b/src/corelib/serialization/qxmlstream.h diff --git a/src/corelib/xml/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h index 5645d812eb..5645d812eb 100644 --- a/src/corelib/xml/qxmlstream_p.h +++ b/src/corelib/serialization/qxmlstream_p.h diff --git a/src/corelib/xml/qxmlutils.cpp b/src/corelib/serialization/qxmlutils.cpp index 01c84251fd..01c84251fd 100644 --- a/src/corelib/xml/qxmlutils.cpp +++ b/src/corelib/serialization/qxmlutils.cpp diff --git a/src/corelib/xml/qxmlutils_p.h b/src/corelib/serialization/qxmlutils_p.h index db6bddd5be..db6bddd5be 100644 --- a/src/corelib/xml/qxmlutils_p.h +++ b/src/corelib/serialization/qxmlutils_p.h diff --git a/src/corelib/serialization/serialization.pri b/src/corelib/serialization/serialization.pri new file mode 100644 index 0000000000..3d039dc30f --- /dev/null +++ b/src/corelib/serialization/serialization.pri @@ -0,0 +1,30 @@ +# Qt data formats core module + +HEADERS += \ + serialization/qdatastream.h \ + serialization/qdatastream_p.h \ + serialization/qjson_p.h \ + serialization/qjsondocument.h \ + serialization/qjsonobject.h \ + serialization/qjsonvalue.h \ + serialization/qjsonarray.h \ + serialization/qjsonwriter_p.h \ + serialization/qjsonparser_p.h \ + serialization/qtextstream.h \ + serialization/qtextstream_p.h \ + serialization/qxmlstream.h \ + serialization/qxmlstream_p.h \ + serialization/qxmlutils_p.h + +SOURCES += \ + serialization/qdatastream.cpp \ + serialization/qjson.cpp \ + serialization/qjsondocument.cpp \ + serialization/qjsonobject.cpp \ + serialization/qjsonarray.cpp \ + serialization/qjsonvalue.cpp \ + serialization/qjsonwriter.cpp \ + serialization/qjsonparser.cpp \ + serialization/qtextstream.cpp \ + serialization/qxmlstream.cpp \ + serialization/qxmlutils.cpp diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index fb5c9fd770..1bb8e613e0 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -311,16 +311,14 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) #ifndef QT_NO_THREAD #if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX)) -static void setCurrentThreadName(pthread_t threadId, const char *name) +static void setCurrentThreadName(const char *name) { # if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) - Q_UNUSED(threadId); prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); # elif defined(Q_OS_MAC) - Q_UNUSED(threadId); pthread_setname_np(name); # elif defined(Q_OS_QNX) - pthread_setname_np(threadId, name); + pthread_setname_np(pthread_self(), name); # endif } #endif @@ -361,14 +359,13 @@ void *QThreadPrivate::start(void *arg) #if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX)) { - // sets the name of the current thread. - QString objectName = thr->objectName(); - - pthread_t thread_id = from_HANDLE<pthread_t>(data->threadId.load()); - if (Q_LIKELY(objectName.isEmpty())) - setCurrentThreadName(thread_id, thr->metaObject()->className()); + // Sets the name of the current thread. We can only do this + // when the thread is starting, as we don't have a cross + // platform way of setting the name of an arbitrary thread. + if (Q_LIKELY(thr->objectName().isEmpty())) + setCurrentThreadName(thr->metaObject()->className()); else - setCurrentThreadName(thread_id, objectName.toLocal8Bit()); + setCurrentThreadName(thr->objectName().toLocal8Bit()); } #endif diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp index 12e4687b3c..f68a807203 100644 --- a/src/corelib/tools/qbitarray.cpp +++ b/src/corelib/tools/qbitarray.cpp @@ -300,6 +300,46 @@ void QBitArray::fill(bool value, int begin, int end) setBit(begin++, value); } +/*! + \fn const char *QBitArray::bits() const + \since 5.11 + + Returns a pointer to a dense bit array for this QBitArray. Bits are counted + upwards from the least significant bit in each byte. The the number of bits + relevant in the last byte is given by \c{size() % 8}. + + \sa fromBits(), size() + */ + +/*! + \since 5.11 + + Creates a QBitArray with the dense bit array located at \a data, with \a + len bits. The byte array at \a data must be at least \a size / 8 (rounded up) + bytes long. + + If \a size is not a multiple of 8, this function will include the lowest + \a size % 8 bits from the last byte in \a data. + + \sa bits() + */ +QBitArray QBitArray::fromBits(const char *data, qsizetype size) +{ + QBitArray result; + qsizetype nbytes = (size + 7) / 8; + + result.d = QByteArray(nbytes + 1, Qt::Uninitialized); + char *bits = result.d.data(); + memcpy(bits + 1, data, nbytes); + + // clear any unused bits from the last byte + if (size & 7) + bits[nbytes] &= 0xffU >> (size & 7); + + *bits = result.d.size() * 8 - size; + return result; +} + /*! \fn bool QBitArray::isDetached() const \internal diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h index 8fa5323127..ff40bf5654 100644 --- a/src/corelib/tools/qbitarray.h +++ b/src/corelib/tools/qbitarray.h @@ -104,6 +104,9 @@ public: inline void truncate(int pos) { if (pos < size()) resize(pos); } + const char *bits() const { return isEmpty() ? nullptr : d.constData() + 1; } + static QBitArray fromBits(const char *data, qsizetype len); + public: typedef QByteArray::DataPtr DataPtr; inline DataPtr &data_ptr() { return d.data_ptr(); } diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index fafc3e37b0..eb56b31348 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -177,55 +177,37 @@ # define QT_FUNCTION_TARGET(x) #endif -#if defined(Q_CC_MSVC) && (defined(_M_AVX) || defined(__AVX__)) -// Visual Studio defines __AVX__ when /arch:AVX is passed, but not the earlier macros -// See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx -// SSE2 is handled by _M_IX86_FP below -# define __SSE3__ 1 -# define __SSSE3__ 1 -// no Intel CPU supports SSE4a, so don't define it -# define __SSE4_1__ 1 -# define __SSE4_2__ 1 -# ifndef __AVX__ -# define __AVX__ 1 -# endif -#endif - -// SSE intrinsics -#if defined(__SSE2__) || (defined(QT_COMPILER_SUPPORTS_SSE2) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -#if defined(QT_LINUXBASE) -/// this is an evil hack - the posix_memalign declaration in LSB -/// is wrong - see http://bugs.linuxbase.org/show_bug.cgi?id=2431 -# define posix_memalign _lsb_hack_posix_memalign -# include <emmintrin.h> -# undef posix_memalign -#else -# include <emmintrin.h> -#endif -#if defined(Q_CC_MSVC) && (defined(_M_X64) || _M_IX86_FP >= 2) -# define __SSE__ 1 -# define __SSE2__ 1 -#endif -#endif +#ifdef Q_PROCESSOR_X86 +/* -- x86 intrinsic support -- */ -// SSE3 intrinsics -#if defined(__SSE3__) || (defined(QT_COMPILER_SUPPORTS_SSE3) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -#include <pmmintrin.h> -#endif +# if defined(Q_CC_MSVC) && (defined(_M_X64) || _M_IX86_FP >= 2) +// MSVC doesn't define __SSE2__, so do it ourselves +# define __SSE__ 1 +# define __SSE2__ 1 +# endif -// SSSE3 intrinsics -#if defined(__SSSE3__) || (defined(QT_COMPILER_SUPPORTS_SSSE3) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -#include <tmmintrin.h> -#endif +# ifdef __SSE2__ +// #include the intrinsics +# include <immintrin.h> +# endif -// SSE4.1 intrinsics -#if defined(__SSE4_1__) || (defined(QT_COMPILER_SUPPORTS_SSE4_1) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -#include <smmintrin.h> -#endif +# if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) +// GCC 4.4 and Clang 2.8 added a few more intrinsics there +# include <x86intrin.h> +# endif -// SSE4.2 intrinsics -#if defined(__SSE4_2__) || (defined(QT_COMPILER_SUPPORTS_SSE4_2) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -#include <nmmintrin.h> +# if defined(Q_CC_MSVC) && (defined(_M_AVX) || defined(__AVX__)) +// Visual Studio defines __AVX__ when /arch:AVX is passed, but not the earlier macros +// See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx +# define __SSE3__ 1 +# define __SSSE3__ 1 +// no Intel CPU supports SSE4a, so don't define it +# define __SSE4_1__ 1 +# define __SSE4_2__ 1 +# ifndef __AVX__ +# define __AVX__ 1 +# endif +# endif # if defined(__SSE4_2__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC)) // POPCNT instructions: @@ -233,13 +215,8 @@ // (but neither MSVC nor the Intel compiler define this macro) # define __POPCNT__ 1 # endif -#endif // AVX intrinsics -#if defined(__AVX__) || (defined(QT_COMPILER_SUPPORTS_AVX) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -// immintrin.h is the ultimate header, we don't need anything else after this -#include <immintrin.h> - # if defined(__AVX__) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS) && (defined(Q_CC_INTEL) || defined(Q_CC_MSVC)) // AES, PCLMULQDQ instructions: // All processors that support AVX support AES, PCLMULQDQ @@ -255,11 +232,6 @@ # define __F16C__ 1 # define __RDRND__ 1 # endif -#endif - -#if defined(__AES__) || defined(__PCLMUL__) || (defined(QT_COMPILER_SUPPORTS_AES) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -# include <wmmintrin.h> -#endif #define QT_FUNCTION_TARGET_STRING_SSE2 "sse2" #define QT_FUNCTION_TARGET_STRING_SSE3 "sse3" @@ -288,19 +260,7 @@ #define QT_FUNCTION_TARGET_STRING_RDSEED "rdseed" #define QT_FUNCTION_TARGET_STRING_SHA "sha" -// other x86 intrinsics -#if defined(Q_PROCESSOR_X86) && ((defined(Q_CC_GNU) && (Q_CC_GNU >= 404)) \ - || (defined(Q_CC_CLANG) && (Q_CC_CLANG >= 208)) \ - || defined(Q_CC_INTEL)) -# define QT_COMPILER_SUPPORTS_X86INTRIN -# ifdef Q_CC_INTEL -// The Intel compiler has no <x86intrin.h> -- all intrinsics are in <immintrin.h>; -# include <immintrin.h> -# else -// GCC 4.4 and Clang 2.8 added a few more intrinsics there -# include <x86intrin.h> -# endif -#endif +#endif /* Q_PROCESSOR_X86 */ // Clang compiler fix, see http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20160222/151168.html // This should be tweaked with an "upper version" of clang once we know which release fixes the diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 5eeaa2a2a8..4040d59b0a 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2018 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -251,6 +251,151 @@ inline RetType UnrollTailLoop<0>::exec(Number, RetType returnIfExited, Functor1, } #endif +#ifdef __SSE2__ +static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval) +{ +# if defined(__AVX2__) + // AVX2 implementation: test 32 bytes at a time + const __m256i mask256 = _mm256_broadcastd_epi32(_mm_cvtsi32_si128(maskval)); + while (ptr + 32 < end) { + __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr)); + if (!_mm256_testz_si256(mask256, data)) + return false; + ptr += 32; + } + + const __m128i mask = _mm256_castsi256_si128(mask256); +# elif defined(__SSE4_1__) + // SSE 4.1 implementation: test 32 bytes at a time (two 16-byte + // comparisons, unrolled) + const __m128i mask = _mm_set1_epi32(maskval); + while (ptr + 32 < end) { + __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr)); + __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr + 16)); + if (!_mm_testz_si128(mask, data1)) + return false; + if (!_mm_testz_si128(mask, data2)) + return false; + ptr += 32; + } +# endif +# if defined(__SSE4_1__) + // AVX2 and SSE4.1: final 16-byte comparison + if (ptr + 16 < end) { + __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr)); + if (!_mm_testz_si128(mask, data1)) + return false; + ptr += 16; + } +# else + // SSE2 implementation: test 16 bytes at a time. + const __m128i mask = _mm_set1_epi32(maskval); + while (ptr + 16 < end) { + __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr)); + __m128i masked = _mm_andnot_si128(mask, data); + __m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128()); + if (quint16(_mm_movemask_epi8(comparison)) != 0xffff) + return false; + ptr += 16; + } +# endif + + return true; +} +#endif + +bool QtPrivate::isAscii(QLatin1String s) Q_DECL_NOTHROW +{ + const char *ptr = s.begin(); + const char *end = s.end(); + +#if defined(__AVX2__) + if (!simdTestMask(ptr, end, 0x80808080)) + return false; +#elif defined(__SSE2__) + // Testing for the high bit can be done efficiently with just PMOVMSKB + while (ptr + 16 < end) { + __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr)); + quint32 mask = _mm_movemask_epi8(data); + if (mask) + return false; + ptr += 16; + } +#endif + + while (ptr + 4 < end) { + quint32 data = qFromUnaligned<quint32>(ptr); + if (data & 0x80808080U) + return false; + ptr += 4; + } + + while (ptr != end) { + if (quint8(*ptr++) & 0x80) + return false; + } + return true; +} + +bool QtPrivate::isAscii(QStringView s) Q_DECL_NOTHROW +{ + const QChar *ptr = s.begin(); + const QChar *end = s.end(); + +#ifdef __SSE2__ + const char *ptr8 = reinterpret_cast<const char *>(ptr); + const char *end8 = reinterpret_cast<const char *>(end); + if (!simdTestMask(ptr8, end8, 0xff80ff80)) + return false; + ptr = reinterpret_cast<const QChar *>(ptr8); +#endif + + while (ptr != end) { + if ((*ptr++).unicode() & 0xff80) + return false; + } + return true; +} + +bool QtPrivate::isLatin1(QStringView s) Q_DECL_NOTHROW +{ + const QChar *ptr = s.begin(); + const QChar *end = s.end(); + +#if defined(__SSE4_1__) + const char *ptr8 = reinterpret_cast<const char *>(ptr); + const char *end8 = reinterpret_cast<const char *>(end); + if (!simdTestMask(ptr8, end8, 0xff00ff00)) + return false; + ptr = reinterpret_cast<const QChar *>(ptr8); +#elif defined(__SSE2__) + // Testing if every other byte is non-zero can be done efficiently by + // using PUNPCKHBW (unpack high order bytes) and comparing that to zero. + while (ptr + 32 < end) { + __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr)); + __m128i data2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr + 16)); + __m128i high = _mm_unpackhi_epi8(data1, data2); + __m128i comparison = _mm_cmpeq_epi16(high, _mm_setzero_si128()); + if (_mm_movemask_epi8(comparison)) + return false; + ptr += 16; + } + if (ptr + 16 < end) { + __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr)); + __m128i high = _mm_unpackhi_epi8(data1, data1); + __m128i comparison = _mm_cmpeq_epi16(high, _mm_setzero_si128()); + if (_mm_movemask_epi8(comparison)) + return false; + } +#endif + + while (ptr != end) { + if ((*ptr++).unicode() > 0xff) + return false; + } + return true; +} + // conversion between Latin 1 and UTF-16 void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW { @@ -2441,6 +2586,21 @@ QString &QString::remove(int pos, int len) return *this; } +template<typename T> +static void removeStringImpl(QString &s, const T &needle, Qt::CaseSensitivity cs) +{ + const int needleSize = needle.size(); + if (needleSize) { + if (needleSize == 1) { + s.remove(needle.front(), cs); + } else { + int i = 0; + while ((i = s.indexOf(needle, i, cs)) != -1) + s.remove(i, needleSize); + } + } +} + /*! Removes every occurrence of the given \a str string in this string, and returns a reference to this string. @@ -2454,11 +2614,27 @@ QString &QString::remove(int pos, int len) */ QString &QString::remove(const QString &str, Qt::CaseSensitivity cs) { - if (str.d->size) { - int i = 0; - while ((i = indexOf(str, i, cs)) != -1) - remove(i, str.d->size); - } + removeStringImpl(*this, str, cs); + return *this; +} + +/*! + \since 5.11 + \overload + + Removes every occurrence of the given \a str string in this + string, and returns a reference to this string. + + If \a cs is Qt::CaseSensitive (default), the search is + case sensitive; otherwise the search is case insensitive. + + This is the same as \c replace(str, "", cs). + + \sa replace() +*/ +QString &QString::remove(QLatin1String str, Qt::CaseSensitivity cs) +{ + removeStringImpl(*this, str, cs); return *this; } diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 808f388c89..0138ae4098 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -202,6 +202,12 @@ Q_DECLARE_TYPEINFO(QLatin1String, Q_MOVABLE_TYPE); typedef QLatin1String QLatin1Literal; // +// QLatin1String inline implementations +// +inline bool QtPrivate::isLatin1(QLatin1String) Q_DECL_NOTHROW +{ return true; } + +// // QStringView members that require QLatin1String: // bool QStringView::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const Q_DECL_NOTHROW @@ -477,6 +483,7 @@ public: QString &remove(int i, int len); QString &remove(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive); + QString &remove(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive); QString &remove(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive); QString &replace(int i, int len, QChar after); QString &replace(int i, int len, const QChar *s, int slen); diff --git a/src/corelib/tools/qstringalgorithms.h b/src/corelib/tools/qstringalgorithms.h index 6146e525d9..8446d85239 100644 --- a/src/corelib/tools/qstringalgorithms.h +++ b/src/corelib/tools/qstringalgorithms.h @@ -82,6 +82,11 @@ Q_REQUIRED_RESULT Q_CORE_EXPORT QByteArray convertToLocal8Bit(QStringView str); Q_REQUIRED_RESULT Q_CORE_EXPORT QVector<uint> convertToUcs4(QStringView str); Q_REQUIRED_RESULT Q_CORE_EXPORT bool isRightToLeft(QStringView string); +Q_REQUIRED_RESULT Q_CORE_EXPORT bool isAscii(QLatin1String s) Q_DECL_NOTHROW; +Q_REQUIRED_RESULT Q_CORE_EXPORT bool isAscii(QStringView s) Q_DECL_NOTHROW; +Q_REQUIRED_RESULT bool isLatin1(QLatin1String s) Q_DECL_NOTHROW; // in qstring.h +Q_REQUIRED_RESULT Q_CORE_EXPORT bool isLatin1(QStringView s) Q_DECL_NOTHROW; + } // namespace QtPRivate QT_END_NAMESPACE diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc index aff2f986e6..336f2afaca 100644 --- a/src/corelib/tools/qvarlengtharray.qdoc +++ b/src/corelib/tools/qvarlengtharray.qdoc @@ -725,8 +725,7 @@ vector. */ -/*! - \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, const T &value) +/*! \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, const T &value) \fn template<class T, int Prealloc> QVarLengthArray<T, Prealloc>::iterator QVarLengthArray<T, Prealloc>::insert(const_iterator before, T &&value) \overload diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc index 173bdb5abf..cc250b72a5 100644 --- a/src/corelib/tools/qvector.qdoc +++ b/src/corelib/tools/qvector.qdoc @@ -607,8 +607,7 @@ \sa append(), insert() */ -/*! - \fn template <typename T> void QVector<T>::insert(int i, const T &value) +/*! \fn template <typename T> void QVector<T>::insert(int i, const T &value) \fn template <typename T> void QVector<T>::insert(int i, T &&value) Inserts \a value at index position \a i in the vector. If \a i is diff --git a/src/corelib/xml/xml.pri b/src/corelib/xml/xml.pri deleted file mode 100644 index 2401c09ab7..0000000000 --- a/src/corelib/xml/xml.pri +++ /dev/null @@ -1,10 +0,0 @@ -# Qt xml core module - -HEADERS += \ - xml/qxmlstream.h \ - xml/qxmlstream_p.h \ - xml/qxmlutils_p.h - -SOURCES += \ - xml/qxmlstream.cpp \ - xml/qxmlutils.cpp diff --git a/src/gui/gui.pro b/src/gui/gui.pro index f8cec00b82..759d6f3cbf 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -95,3 +95,6 @@ qtConfig(angle) { qtConfig(egl): CMAKE_EGL_INCDIRS = $$cmakePortablePaths($$QMAKE_INCDIR_EGL) QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist + +TRACEPOINT_PROVIDER = $$PWD/qtgui.tracepoints +CONFIG += qt_tracepoints diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp index 519995e82a..d1e0604caf 100644 --- a/src/gui/itemmodels/qstandarditemmodel.cpp +++ b/src/gui/itemmodels/qstandarditemmodel.cpp @@ -278,8 +278,24 @@ void QStandardItemPrivate::setItemData(const QMap<int, QVariant> &roles) if (newValues != values) { values.swap(newValues); - if (model) - model->d_func()->itemChanged(q); + if (model) { + QVector<int> roleKeys; + roleKeys.reserve(roles.size() + 1); + bool hasEditRole = false; + bool hasDisplayRole = false; + for (auto it = roles.keyBegin(); it != roles.keyEnd(); ++it) { + roleKeys.push_back(*it); + if (*it == Qt::EditRole) + hasEditRole = true; + else if (*it == Qt::DisplayRole) + hasDisplayRole = true; + } + if (hasEditRole && !hasDisplayRole) + roleKeys.push_back(Qt::DisplayRole); + else if (!hasEditRole && hasDisplayRole) + roleKeys.push_back(Qt::EditRole); + model->d_func()->itemChanged(q, roleKeys); + } } } @@ -554,7 +570,7 @@ bool QStandardItemPrivate::insertColumns(int column, int count, const QList<QSta /*! \internal */ -void QStandardItemModelPrivate::itemChanged(QStandardItem *item) +void QStandardItemModelPrivate::itemChanged(QStandardItem *item, const QVector<int> &roles) { Q_Q(QStandardItemModel); Q_ASSERT(item); @@ -570,8 +586,8 @@ void QStandardItemModelPrivate::itemChanged(QStandardItem *item) } } else { // Normal item - QModelIndex index = q->indexFromItem(item); - emit q->dataChanged(index, index); + const QModelIndex index = q->indexFromItem(item); + emit q->dataChanged(index, index, roles); } } @@ -885,6 +901,9 @@ void QStandardItem::setData(const QVariant &value, int role) { Q_D(QStandardItem); role = (role == Qt::EditRole) ? Qt::DisplayRole : role; + const QVector<int> roles((role == Qt::DisplayRole) ? + QVector<int>({Qt::DisplayRole, Qt::EditRole}) : + QVector<int>({role})); QVector<QStandardItemData>::iterator it; for (it = d->values.begin(); it != d->values.end(); ++it) { if ((*it).role == role) { @@ -896,13 +915,13 @@ void QStandardItem::setData(const QVariant &value, int role) d->values.erase(it); } if (d->model) - d->model->d_func()->itemChanged(this); + d->model->d_func()->itemChanged(this, roles); return; } } d->values.append(QStandardItemData(role, value)); if (d->model) - d->model->d_func()->itemChanged(this); + d->model->d_func()->itemChanged(this, roles); } /*! diff --git a/src/gui/itemmodels/qstandarditemmodel.h b/src/gui/itemmodels/qstandarditemmodel.h index c54e7b27d9..d8f06b629a 100644 --- a/src/gui/itemmodels/qstandarditemmodel.h +++ b/src/gui/itemmodels/qstandarditemmodel.h @@ -419,6 +419,7 @@ public: bool dropMimeData (const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; Q_SIGNALS: + // ### Qt 6: add changed roles void itemChanged(QStandardItem *item); protected: diff --git a/src/gui/itemmodels/qstandarditemmodel_p.h b/src/gui/itemmodels/qstandarditemmodel_p.h index caee3ea34c..bd28ec3029 100644 --- a/src/gui/itemmodels/qstandarditemmodel_p.h +++ b/src/gui/itemmodels/qstandarditemmodel_p.h @@ -200,7 +200,7 @@ public: } void sort(QStandardItem *parent, int column, Qt::SortOrder order); - void itemChanged(QStandardItem *item); + void itemChanged(QStandardItem *item, const QVector<int> &roles = QVector<int>()); void rowsAboutToBeInserted(QStandardItem *parent, int start, int end); void columnsAboutToBeInserted(QStandardItem *parent, int start, int end); void rowsAboutToBeRemoved(QStandardItem *parent, int start, int end); diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index be8ce1a011..50d9bbb2cc 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3761,14 +3761,25 @@ static inline void formatInputMethodEvent(QDebug d, const QInputMethodEvent *e) static inline void formatInputMethodQueryEvent(QDebug d, const QInputMethodQueryEvent *e) { + QDebugStateSaver saver(d); + d.noquote(); const Qt::InputMethodQueries queries = e->queries(); d << "QInputMethodQueryEvent(queries=" << showbase << hex << int(queries) << noshowbase << dec << ", {"; - for (unsigned mask = 1; mask <= Qt::ImTextAfterCursor; mask<<=1) { + for (unsigned mask = 1; mask <= Qt::ImInputItemClipRectangle; mask<<=1) { if (queries & mask) { - const QVariant value = e->value(static_cast<Qt::InputMethodQuery>(mask)); - if (value.isValid()) - d << '[' << showbase << hex << mask << noshowbase << dec << '=' << value << "],"; + const Qt::InputMethodQuery query = static_cast<Qt::InputMethodQuery>(mask); + const QVariant value = e->value(query); + if (value.isValid()) { + d << '['; + QtDebugUtils::formatQEnum(d, query); + d << '='; + if (query == Qt::ImHints) + QtDebugUtils::formatQFlags(d, Qt::InputMethodHints(value.toInt())); + else + d << value.toString(); + d << "],"; + } } } d << "})"; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 5f4a1a0236..055347500b 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -111,6 +111,8 @@ # include <QtCore/QLibraryInfo> #endif // Q_OS_WIN +#include <qtgui_tracepoints_p.h> + #include <ctype.h> QT_BEGIN_NAMESPACE @@ -1360,6 +1362,8 @@ void QGuiApplicationPrivate::eventDispatcherReady() void QGuiApplicationPrivate::init() { + Q_TRACE(qguiapplicationprivate_init_entry); + #if defined(Q_OS_MACOS) QMacAutoReleasePool pool; #endif @@ -1522,6 +1526,8 @@ void QGuiApplicationPrivate::init() if (!QGuiApplicationPrivate::displayName) QObject::connect(q, &QGuiApplication::applicationNameChanged, q, &QGuiApplication::applicationDisplayNameChanged); + + Q_TRACE(qguiapplicationprivate_init_exit); } extern void qt_cleanupFontDatabase(); @@ -1756,6 +1762,8 @@ bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArra void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) { + Q_TRACE(qguiapplicationprivate_processwsevents_entry, e->type); + switch(e->type) { case QWindowSystemInterfacePrivate::Mouse: QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e)); @@ -1864,6 +1872,8 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv qWarning() << "Unknown user input event type:" << e->type; break; } + + Q_TRACE(qguiapplicationprivate_processwsevents_exit, e->type); } /*! \internal diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 151151de23..448d670209 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -418,6 +418,8 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const return QPlatformTheme::defaultThemeHint(QPlatformTheme::UiEffects); case WheelScrollLines: return QPlatformTheme::defaultThemeHint(QPlatformTheme::WheelScrollLines); + case MouseQuickSelectionThreshold: + return QPlatformTheme::defaultThemeHint(QPlatformTheme::MouseQuickSelectionThreshold); } return 0; diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index a7d9a87502..37884e1f78 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -164,6 +164,7 @@ public: UiEffects, WheelScrollLines, ShowShortcutsInContextMenus, + MouseQuickSelectionThreshold }; virtual QVariant styleHint(StyleHint hint) const; diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index 1856952805..277d976dde 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -559,6 +559,8 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint) dist = defaultThemeHint(MouseDoubleClickDistance).toInt(&ok) * 2; return QVariant(ok ? dist : 10); } + case MouseQuickSelectionThreshold: + return QVariant(10); } return QVariant(); } diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index 87873d446f..1d6049a98d 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -117,7 +117,8 @@ public: WheelScrollLines, TouchDoubleTapDistance, ShowShortcutsInContextMenus, - IconFallbackSearchPaths + IconFallbackSearchPaths, + MouseQuickSelectionThreshold }; enum DialogType { diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp index 0850228ee5..b2d968c046 100644 --- a/src/gui/kernel/qstylehints.cpp +++ b/src/gui/kernel/qstylehints.cpp @@ -79,6 +79,7 @@ public: , m_tabFocusBehavior(-1) , m_uiEffects(-1) , m_wheelScrollLines(-1) + , m_mouseQuickSelectionThreshold(-1) {} int m_mouseDoubleClickInterval; @@ -90,6 +91,7 @@ public: int m_tabFocusBehavior; int m_uiEffects; int m_wheelScrollLines; + int m_mouseQuickSelectionThreshold; }; /*! @@ -537,4 +539,38 @@ void QStyleHints::setWheelScrollLines(int scrollLines) emit wheelScrollLinesChanged(scrollLines); } +/*! + Sets the mouse quick selection threshold. + \internal + \sa mouseQuickSelectionThreshold() + \since 5.11 +*/ +void QStyleHints::setMouseQuickSelectionThreshold(int threshold) +{ + Q_D(QStyleHints); + if (d->m_mouseQuickSelectionThreshold == threshold) + return; + d->m_mouseQuickSelectionThreshold = threshold; + emit mouseDoubleClickIntervalChanged(threshold); +} + +/*! + \property QStyleHints::mouseQuickSelectionThreshold + \brief Quick selection mouse threshold in QLineEdit. + + This property defines how much the mouse cursor should be moved along the y axis + to trigger a quick selection during a normal QLineEdit text selection. + + If the property value is less than or equal to 0, the quick selection feature is disabled. + + \since 5.11 +*/ +int QStyleHints::mouseQuickSelectionThreshold() const +{ + Q_D(const QStyleHints); + if (d->m_mouseQuickSelectionThreshold >= 0) + return d->m_mouseQuickSelectionThreshold; + return themeableHint(QPlatformTheme::MouseQuickSelectionThreshold, QPlatformIntegration::MouseQuickSelectionThreshold).toInt(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h index 2c2e048b15..7b0683e9b1 100644 --- a/src/gui/kernel/qstylehints.h +++ b/src/gui/kernel/qstylehints.h @@ -73,6 +73,7 @@ class Q_GUI_EXPORT QStyleHints : public QObject Q_PROPERTY(bool singleClickActivation READ singleClickActivation STORED false CONSTANT FINAL) Q_PROPERTY(bool useHoverEffects READ useHoverEffects WRITE setUseHoverEffects NOTIFY useHoverEffectsChanged FINAL) Q_PROPERTY(int wheelScrollLines READ wheelScrollLines NOTIFY wheelScrollLinesChanged FINAL) + Q_PROPERTY(int mouseQuickSelectionThreshold READ mouseQuickSelectionThreshold WRITE setMouseQuickSelectionThreshold NOTIFY mouseQuickSelectionThresholdChanged FINAL) public: void setMouseDoubleClickInterval(int mouseDoubleClickInterval); @@ -104,6 +105,8 @@ public: void setUseHoverEffects(bool useHoverEffects); int wheelScrollLines() const; void setWheelScrollLines(int scrollLines); + void setMouseQuickSelectionThreshold(int threshold); + int mouseQuickSelectionThreshold() const; Q_SIGNALS: void cursorFlashTimeChanged(int cursorFlashTime); @@ -115,6 +118,7 @@ Q_SIGNALS: void tabFocusBehaviorChanged(Qt::TabFocusBehavior tabFocusBehavior); void useHoverEffectsChanged(bool useHoverEffects); void wheelScrollLinesChanged(int scrollLines); + void mouseQuickSelectionThresholdChanged(int threshold); private: friend class QGuiApplication; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 6ddfcdfaf4..23c8e42ded 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -174,29 +174,31 @@ template<QImage::Format Format> static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { - Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); - Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); - Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); + auto conversion = [](uint s) { + // MSVC needs these constexpr defined in here otherwise it will create a capture. + Q_CONSTEXPR uint redMask = ((1 << redWidth<Format>()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth<Format>()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth<Format>()) - 1); - Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); - Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); - Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth<Format>(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth<Format>(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth<Format>(); - Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; - Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; - Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; + Q_CONSTEXPR uchar redRightShift = 2 * redWidth<Format>() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth<Format>() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth<Format>() - 8; - for (int i = 0; i < count; ++i) { - uint red = (src[i] >> redShift<Format>()) & redMask; - uint green = (src[i] >> greenShift<Format>()) & greenMask; - uint blue = (src[i] >> blueShift<Format>()) & blueMask; + uint red = (s >> redShift<Format>()) & redMask; + uint green = (s >> greenShift<Format>()) & greenMask; + uint blue = (s >> blueShift<Format>()) & blueMask; red = ((red << redLeftShift) | (red >> redRightShift)) << 16; green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; blue = (blue << blueLeftShift) | (blue >> blueRightShift); - buffer[i] = 0xff000000 | red | green | blue; - } + return 0xff000000 | red | green | blue; + }; + UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion); return buffer; } @@ -348,21 +350,21 @@ static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint * // RGB32 -> RGB888 is not a precision loss. if (!dither || (rWidth == 8 && gWidth == 8 && bWidth == 8)) { - Q_CONSTEXPR uint rMask = (1 << rWidth) - 1; - Q_CONSTEXPR uint gMask = (1 << gWidth) - 1; - Q_CONSTEXPR uint bMask = (1 << bWidth) - 1; + auto conversion = [](uint s) { + const uint c = fromRGB ? s : qUnpremultiply(s); + Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1; + Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1; + Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1; + Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>(); + Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>(); + Q_CONSTEXPR uchar bRightShift = 8 - blueWidth<Format>(); - Q_CONSTEXPR uchar rRightShift = 24 - rWidth; - Q_CONSTEXPR uchar gRightShift = 16 - gWidth; - Q_CONSTEXPR uchar bRightShift = 8 - bWidth; - - for (int i = 0; i < count; ++i) { - const uint c = fromRGB ? src[i] : qUnpremultiply(src[i]); const uint r = ((c >> rRightShift) & rMask) << redShift<Format>(); const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>(); const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>(); - buffer[i] = r | g | b; - } + return r | g | b; + }; + UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion); } else { // We do ordered dither by using a rounding conversion, but instead of // adding half of input precision, we add the adjusted result from the @@ -394,32 +396,32 @@ template<QImage::Format Format, bool fromRGB> static const uint *QT_FASTCALL convertARGBPMFromARGB32PM(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *dither) { - Q_CONSTEXPR uchar aWidth = alphaWidth<Format>(); - Q_CONSTEXPR uchar rWidth = redWidth<Format>(); - Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); - Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); - if (!dither) { - Q_CONSTEXPR uint aMask = (1 << aWidth) - 1; - Q_CONSTEXPR uint rMask = (1 << rWidth) - 1; - Q_CONSTEXPR uint gMask = (1 << gWidth) - 1; - Q_CONSTEXPR uint bMask = (1 << bWidth) - 1; - - Q_CONSTEXPR uchar aRightShift = 32 - aWidth; - Q_CONSTEXPR uchar rRightShift = 24 - rWidth; - Q_CONSTEXPR uchar gRightShift = 16 - gWidth; - Q_CONSTEXPR uchar bRightShift = 8 - bWidth; - - Q_CONSTEXPR uint aOpaque = aMask << alphaShift<Format>(); - for (int i = 0; i < count; ++i) { - const uint c = src[i]; + auto conversion = [](uint c) { + Q_CONSTEXPR uint aMask = (1 << alphaWidth<Format>()) - 1; + Q_CONSTEXPR uint rMask = (1 << redWidth<Format>()) - 1; + Q_CONSTEXPR uint gMask = (1 << greenWidth<Format>()) - 1; + Q_CONSTEXPR uint bMask = (1 << blueWidth<Format>()) - 1; + + Q_CONSTEXPR uchar aRightShift = 32 - alphaWidth<Format>(); + Q_CONSTEXPR uchar rRightShift = 24 - redWidth<Format>(); + Q_CONSTEXPR uchar gRightShift = 16 - greenWidth<Format>(); + Q_CONSTEXPR uchar bRightShift = 8 - blueWidth<Format>(); + + Q_CONSTEXPR uint aOpaque = aMask << alphaShift<Format>(); const uint a = fromRGB ? aOpaque : (((c >> aRightShift) & aMask) << alphaShift<Format>()); const uint r = ((c >> rRightShift) & rMask) << redShift<Format>(); const uint g = ((c >> gRightShift) & gMask) << greenShift<Format>(); const uint b = ((c >> bRightShift) & bMask) << blueShift<Format>(); - buffer[i] = a | r | g | b; - } + return a | r | g | b; + }; + UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion); } else { + Q_CONSTEXPR uchar aWidth = alphaWidth<Format>(); + Q_CONSTEXPR uchar rWidth = redWidth<Format>(); + Q_CONSTEXPR uchar gWidth = greenWidth<Format>(); + Q_CONSTEXPR uchar bWidth = blueWidth<Format>(); + const uint *bayer_line = qt_bayer_matrix[dither->y & 15]; for (int i = 0; i < count; ++i) { const uint c = src[i]; @@ -514,8 +516,7 @@ static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint static const uint *QT_FASTCALL convertRGBA8888PMToARGB32PM(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = RGBA2ARGB(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, RGBA2ARGB); return buffer; } @@ -568,8 +569,7 @@ static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uin static const uint *QT_FASTCALL convertRGBA8888PMFromARGB32PM(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, ARGB2RGBA); return buffer; } @@ -695,8 +695,7 @@ static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const u static const uint *QT_FASTCALL convertRGBXFromRGB32(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(0xff000000 | src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint c) { return ARGB2RGBA(0xff000000 | c); }); return buffer; } @@ -713,8 +712,7 @@ static const uint *QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, const ui const QVector<QRgb> *, QDitherInfo *dither) { if (!dither) { - for (int i = 0; i < count; ++i) - buffer[i] = qConvertA2rgb30ToArgb32<PixelOrder>(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertA2rgb30ToArgb32<PixelOrder>); } else { for (int i = 0; i < count; ++i) { const uint c = src[i]; @@ -796,8 +794,7 @@ template<QtPixelOrder PixelOrder> static const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = qConvertArgb32ToA2rgb30<PixelOrder>(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertArgb32ToA2rgb30<PixelOrder>); return buffer; } @@ -814,8 +811,7 @@ template<QtPixelOrder PixelOrder> static const uint *QT_FASTCALL convertRGB30FromARGB32PM(uint *buffer, const uint *src, int count, const QVector<QRgb> *, QDitherInfo *) { - for (int i = 0; i < count; ++i) - buffer[i] = qConvertRgb32ToRgb30<PixelOrder>(qUnpremultiply(src[i])); + UNALIASED_CONVERSION_LOOP(buffer, src, count, qConvertRgb32ToRgb30<PixelOrder>); return buffer; } diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp index cf89f408b5..3a70524a9d 100644 --- a/src/gui/painting/qdrawhelper_avx2.cpp +++ b/src/gui/painting/qdrawhelper_avx2.cpp @@ -427,7 +427,7 @@ void QT_FASTCALL comp_func_Source_rgb64_avx2(QRgba64 *dst, const QRgba64 *src, i ::memcpy(dst, src, length * sizeof(QRgba64)); } else { const uint ca = const_alpha | (const_alpha << 8); // adjust to [0-65535] - const uint cia = 65535 - const_alpha; + const uint cia = 65535 - ca; int x = 0; @@ -493,7 +493,7 @@ void QT_FASTCALL comp_func_solid_SourceOver_rgb64_avx2(QRgba64 *destPixels, int if (const_alpha != 255) color = multiplyAlpha255(color, const_alpha); - const uint minusAlphaOfColor = ~ushort(color.alpha()); + const uint minusAlphaOfColor = 65535 - color.alpha(); int x = 0; quint64 *dst = (quint64 *) destPixels; const __m256i colorVector = _mm256_set1_epi64x(color); diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 4c2fe87355..ebf215a3eb 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -1104,22 +1104,30 @@ inline int qBlue565(quint16 rgb) { return (b << 3) | (b >> 2); } +// We manually unalias the variables to make sure the compiler +// fully optimizes both aliased and unaliased cases. +#define UNALIASED_CONVERSION_LOOP(buffer, src, count, conversion) \ + if (src == buffer) { \ + for (int i = 0; i < count; ++i) \ + buffer[i] = conversion(buffer[i]); \ + } else { \ + for (int i = 0; i < count; ++i) \ + buffer[i] = conversion(src[i]); \ + } + static Q_ALWAYS_INLINE const uint *qt_convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count) { - for (int i = 0; i < count; ++i) - buffer[i] = qPremultiply(src[i]); + UNALIASED_CONVERSION_LOOP(buffer, src, count, qPremultiply); return buffer; } static Q_ALWAYS_INLINE const uint *qt_convertRGBA8888ToARGB32PM(uint *buffer, const uint *src, int count) { - for (int i = 0; i < count; ++i) - buffer[i] = qPremultiply(RGBA2ARGB(src[i])); + UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) { return qPremultiply(RGBA2ARGB(s));}); return buffer; } - const uint qt_bayer_matrix[16][16] = { { 0x1, 0xc0, 0x30, 0xf0, 0xc, 0xcc, 0x3c, 0xfc, 0x3, 0xc3, 0x33, 0xf3, 0xf, 0xcf, 0x3f, 0xff}, diff --git a/src/gui/qtgui.tracepoints b/src/gui/qtgui.tracepoints new file mode 100644 index 0000000000..aa8a8ede57 --- /dev/null +++ b/src/gui/qtgui.tracepoints @@ -0,0 +1,8 @@ +qfontdatabase_addapplicationfont(const QString &filename) +qfontdatabase_load(const QString &family, int pointSize) +qfontdatabase_loadengine(const QString &family, int pointSize) +qfontdatabaseprivate_addappfont(const QString &fileName) +qguiapplicationprivate_init_entry() +qguiapplicationprivate_init_exit() +qguiapplicationprivate_processwsevents_entry(int type) +qguiapplicationprivate_processwsevents_exit(int type) diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 4be2197c68..404a722e29 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -74,6 +74,7 @@ # define FM_DEBUG if (false) qDebug #endif +#include <qtgui_tracepoints_p.h> QT_BEGIN_NAMESPACE @@ -1009,6 +1010,8 @@ QFontEngine *loadEngine(int script, const QFontDef &request, QFontEngine *engine = loadSingleEngine(script, request, family, foundry, style, size); if (engine && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) { + Q_TRACE(qfontdatabase_loadengine, request.family, request.pointSize); + QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QChar::Script(script)); if (!request.fallBackFamilies.isEmpty()) { @@ -2439,6 +2442,8 @@ int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString & font.data = fontData; font.fileName = fileName; + Q_TRACE(qfontdatabaseprivate_addappfont, fileName); + int i; for (i = 0; i < applicationFonts.count(); ++i) if (applicationFonts.at(i).families.isEmpty()) @@ -2494,6 +2499,9 @@ int QFontDatabase::addApplicationFont(const QString &fileName) QFile f(fileName); if (!f.open(QIODevice::ReadOnly)) return -1; + + Q_TRACE(qfontdatabase_addapplicationfont, fileName); + data = f.readAll(); } QMutexLocker locker(fontDatabaseMutex()); @@ -2792,6 +2800,8 @@ void QFontDatabase::load(const QFontPrivate *d, int script) QFontEngine *fe = nullptr; + Q_TRACE(qfontdatabase_load, req.family, req.pointSize); + req.fallBackFamilies = fallBackFamilies; if (!req.fallBackFamilies.isEmpty()) req.family = req.fallBackFamilies.takeFirst(); diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 99f72a7955..1d7c5bec51 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -308,7 +308,7 @@ QT_BEGIN_NAMESPACE was specified, QNetworkAccessManager gives up, without attempting to fall back to HTTP/1.1. If both HTTP2AllowedAttribute and Http2DirectAttribute are set, Http2DirectAttribute takes priority. - (This value was introduced in 5.10.) + (This value was introduced in 5.11.) \omitvalue ResourceTypeAttribute diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index 75a880f115..cbbbac85fe 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -221,6 +221,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const d->peerVerifyMode == other.d->peerVerifyMode && d->peerVerifyDepth == other.d->peerVerifyDepth && d->allowRootCertOnDemandLoading == other.d->allowRootCertOnDemandLoading && + d->backendConfig == other.d->backendConfig && d->sslOptions == other.d->sslOptions && d->sslSession == other.d->sslSession && d->sslSessionTicketLifeTimeHint == other.d->sslSessionTicketLifeTimeHint && @@ -263,6 +264,7 @@ bool QSslConfiguration::isNull() const d->privateKey.isNull() && d->peerCertificate.isNull() && d->peerCertificateChain.count() == 0 && + d->backendConfig.isEmpty() && d->sslOptions == QSslConfigurationPrivate::defaultSslOptions && d->sslSession.isNull() && d->sslSessionTicketLifeTimeHint == -1 && @@ -870,6 +872,60 @@ void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParame } /*! + \since 5.11 + + Returns the backend-specific configuration. + + Only options set by addBackendConfig() or setBackendConfig() will be + returned. The internal standard configuration of the backend is not reported. + + \sa setBackendConfigOption(), setBackendConfig() + */ +QMap<QByteArray, QVariant> QSslConfiguration::backendConfig() const +{ + return d->backendConfig; +} + +/*! + \since 5.11 + + Sets an option in the backend-specific configuration. + + Options supported by the OpenSSL (>= 1.0.2) backend are available in the \l + {https://www.openssl.org/docs/manmaster/man3/SSL_CONF_cmd.html#SUPPORTED-CONFIGURATION-FILE-COMMANDS} + {supported configuration file commands} documentation. The expected type for + the \a value parameter is a QByteArray for all options. The \l + {https://www.openssl.org/docs/manmaster/man3/SSL_CONF_cmd.html#EXAMPLES}{examples} + show how to use some of the options. + + \note The backend-specific configuration will be applied after the general + configuration. Using the backend-specific configuration to set a general + configuration option again will overwrite the general configuration option. + + \sa backendConfig(), setBackendConfig() + */ +void QSslConfiguration::setBackendConfigOption(const QByteArray &name, const QVariant &value) +{ + d->backendConfig[name] = value; +} + +/*! + \since 5.11 + + Sets or clears the backend-specific configuration. + + Without a \a backendConfig parameter this function will clear the + backend-specific configuration. More information about the supported + options is available in the documentation of addBackendConfig(). + + \sa backendConfig(), setBackendConfigOption() + */ +void QSslConfiguration::setBackendConfig(const QMap<QByteArray, QVariant> &backendConfig) +{ + d->backendConfig = backendConfig; +} + +/*! \since 5.3 This function returns the protocol negotiated with the server diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index 1c57bebd65..b3264126dd 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -57,6 +57,7 @@ #define QSSLCONFIGURATION_H #include <QtNetwork/qtnetworkglobal.h> +#include <QtCore/qmap.h> #include <QtCore/qshareddata.h> #include <QtNetwork/qsslsocket.h> #include <QtNetwork/qssl.h> @@ -149,6 +150,10 @@ public: QSslDiffieHellmanParameters diffieHellmanParameters() const; void setDiffieHellmanParameters(const QSslDiffieHellmanParameters &dhparams); + QMap<QByteArray, QVariant> backendConfig() const; + void setBackendConfigOption(const QByteArray &name, const QVariant &value); + void setBackendConfig(const QMap<QByteArray, QVariant> &backendConfig = QMap<QByteArray, QVariant>()); + static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h index 6adf2c9b54..38a98239db 100644 --- a/src/network/ssl/qsslconfiguration_p.h +++ b/src/network/ssl/qsslconfiguration_p.h @@ -67,6 +67,7 @@ // We mean it. // +#include <QtCore/qmap.h> #include <QtNetwork/private/qtnetworkglobal_p.h> #include "qsslconfiguration.h" #include "qlist.h" @@ -123,6 +124,8 @@ public: QSslDiffieHellmanParameters dhParams; + QMap<QByteArray, QVariant> backendConfig; + QByteArray sslSession; int sslSessionTicketLifeTimeHint; diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp index cef503710c..386c280659 100644 --- a/src/network/ssl/qsslcontext_openssl.cpp +++ b/src/network/ssl/qsslcontext_openssl.cpp @@ -49,6 +49,11 @@ QT_BEGIN_NAMESPACE +static inline QString msgErrorSettingBackendConfig(const QString &why) +{ + return QSslSocket::tr("Error when setting the OpenSSL configuration (%1)").arg(why); +} + QSslContext::QSslContext() : ctx(0), pkey(0), @@ -237,4 +242,70 @@ QString QSslContext::errorString() const return errorStr; } +// static +void QSslContext::applyBackendConfig(QSslContext *sslContext) +{ + if (sslContext->sslConfiguration.backendConfig().isEmpty()) + return; + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (QSslSocket::sslLibraryVersionNumber() >= 0x10002000L) { + QSharedPointer<SSL_CONF_CTX> cctx(q_SSL_CONF_CTX_new(), &q_SSL_CONF_CTX_free); + if (cctx) { + q_SSL_CONF_CTX_set_ssl_ctx(cctx.data(), sslContext->ctx); + q_SSL_CONF_CTX_set_flags(cctx.data(), SSL_CONF_FLAG_FILE); + + const auto &backendConfig = sslContext->sslConfiguration.backendConfig(); + for (auto i = backendConfig.constBegin(); i != backendConfig.constEnd(); ++i) { + if (!i.value().canConvert(QMetaType::QByteArray)) { + sslContext->errorCode = QSslError::UnspecifiedError; + sslContext->errorStr = msgErrorSettingBackendConfig( + QSslSocket::tr("Expecting QByteArray for %1").arg( + QString::fromUtf8(i.key()))); + return; + } + + const QByteArray &value = i.value().toByteArray(); + const int result = q_SSL_CONF_cmd(cctx.data(), i.key().constData(), value.constData()); + if (result == 2) + continue; + + sslContext->errorCode = QSslError::UnspecifiedError; + switch (result) { + case 0: + sslContext->errorStr = msgErrorSettingBackendConfig( + QSslSocket::tr("An error occurred attempting to set %1 to %2").arg( + QString::fromUtf8(i.key()), QString::fromUtf8(value))); + return; + case 1: + sslContext->errorStr = msgErrorSettingBackendConfig( + QSslSocket::tr("Wrong value for %1 (%2)").arg( + QString::fromUtf8(i.key()), QString::fromUtf8(value))); + return; + default: + sslContext->errorStr = msgErrorSettingBackendConfig( + QSslSocket::tr("Unrecognized command %1 = %2").arg( + QString::fromUtf8(i.key()), QString::fromUtf8(value))); + return; + } + } + + if (q_SSL_CONF_CTX_finish(cctx.data()) == 0) { + sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_finish() failed")); + sslContext->errorCode = QSslError::UnspecifiedError; + } + } else { + sslContext->errorStr = msgErrorSettingBackendConfig(QSslSocket::tr("SSL_CONF_CTX_new() failed")); + sslContext->errorCode = QSslError::UnspecifiedError; + } + } else +#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L + { + // specific algorithms requested, but not possible to set + sslContext->errorCode = QSslError::UnspecifiedError; + sslContext->errorStr = msgErrorSettingBackendConfig( + QSslSocket::tr("OpenSSL version too old, need at least v1.0.2")); + } +} + QT_END_NAMESPACE diff --git a/src/network/ssl/qsslcontext_openssl11.cpp b/src/network/ssl/qsslcontext_openssl11.cpp index 787b6ae3f5..7be7be46b8 100644 --- a/src/network/ssl/qsslcontext_openssl11.cpp +++ b/src/network/ssl/qsslcontext_openssl11.cpp @@ -260,6 +260,7 @@ init_context: #ifdef OPENSSL_NO_EC sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves")); sslContext->errorCode = QSslError::UnspecifiedError; + return; #else // Set the curves to be used. std::vector<int> curves; @@ -269,9 +270,12 @@ init_context: if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) { sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); sslContext->errorCode = QSslError::UnspecifiedError; + return; } #endif } + + applyBackendConfig(sslContext); } QT_END_NAMESPACE diff --git a/src/network/ssl/qsslcontext_openssl_p.h b/src/network/ssl/qsslcontext_openssl_p.h index 06a31af5e5..48beebf134 100644 --- a/src/network/ssl/qsslcontext_openssl_p.h +++ b/src/network/ssl/qsslcontext_openssl_p.h @@ -107,6 +107,7 @@ protected: private: static void initSslContext(QSslContext* sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading); + static void applyBackendConfig(QSslContext *sslContext); private: SSL_CTX* ctx; diff --git a/src/network/ssl/qsslcontext_opensslpre11.cpp b/src/network/ssl/qsslcontext_opensslpre11.cpp index 9c01c2f2dc..eea821804f 100644 --- a/src/network/ssl/qsslcontext_opensslpre11.cpp +++ b/src/network/ssl/qsslcontext_opensslpre11.cpp @@ -340,6 +340,7 @@ init_context: const_cast<int *>(reinterpret_cast<const int *>(qcurves.data())))) { sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); sslContext->errorCode = QSslError::UnspecifiedError; + return; } } else #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC) @@ -347,8 +348,11 @@ init_context: // specific curves requested, but not possible to set -> error sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version too old, need at least v1.0.2")); sslContext->errorCode = QSslError::UnspecifiedError; + return; } } + + applyBackendConfig(sslContext); } QT_END_NAMESPACE diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 9f07b53e4b..833d676192 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -922,6 +922,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) d->configuration.peerVerifyDepth = configuration.peerVerifyDepth(); d->configuration.peerVerifyMode = configuration.peerVerifyMode(); d->configuration.protocol = configuration.protocol(); + d->configuration.backendConfig = configuration.backendConfig(); d->configuration.sslOptions = configuration.d->sslOptions; d->configuration.sslSession = configuration.sessionTicket(); d->configuration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint(); @@ -2256,6 +2257,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri ptr->peerVerifyDepth = global->peerVerifyDepth; ptr->sslOptions = global->sslOptions; ptr->ellipticCurves = global->ellipticCurves; + ptr->backendConfig = global->backendConfig; } /*! diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index 1b73135935..9bb67771fd 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -402,6 +402,14 @@ DEFINEFUNC2(int, SSL_CTX_use_PrivateKey, SSL_CTX *a, a, EVP_PKEY *b, b, return - DEFINEFUNC2(int, SSL_CTX_use_RSAPrivateKey, SSL_CTX *a, a, RSA *b, b, return -1, return) DEFINEFUNC3(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return) DEFINEFUNC(X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *a, a, return 0, return) +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +DEFINEFUNC(SSL_CONF_CTX *, SSL_CONF_CTX_new, DUMMYARG, DUMMYARG, return 0, return); +DEFINEFUNC(void, SSL_CONF_CTX_free, SSL_CONF_CTX *a, a, return ,return); +DEFINEFUNC2(void, SSL_CONF_CTX_set_ssl_ctx, SSL_CONF_CTX *a, a, SSL_CTX *b, b, return, return); +DEFINEFUNC2(unsigned int, SSL_CONF_CTX_set_flags, SSL_CONF_CTX *a, a, unsigned int b, b, return 0, return); +DEFINEFUNC(int, SSL_CONF_CTX_finish, SSL_CONF_CTX *a, a, return 0, return); +DEFINEFUNC3(int, SSL_CONF_cmd, SSL_CONF_CTX *a, a, const char *b, b, const char *c, c, return 0, return); +#endif DEFINEFUNC(void, SSL_free, SSL *a, a, return, DUMMYARG) DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, const SSL *a, a, return 0, return) #if OPENSSL_VERSION_NUMBER >= 0x10000000L @@ -1105,6 +1113,14 @@ bool q_resolveOpenSslSymbols() RESOLVEFUNC(SSL_CTX_use_RSAPrivateKey) RESOLVEFUNC(SSL_CTX_use_PrivateKey_file) RESOLVEFUNC(SSL_CTX_get_cert_store); +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + RESOLVEFUNC(SSL_CONF_CTX_new); + RESOLVEFUNC(SSL_CONF_CTX_free); + RESOLVEFUNC(SSL_CONF_CTX_set_ssl_ctx); + RESOLVEFUNC(SSL_CONF_CTX_set_flags); + RESOLVEFUNC(SSL_CONF_CTX_finish); + RESOLVEFUNC(SSL_CONF_cmd); +#endif RESOLVEFUNC(SSL_accept) RESOLVEFUNC(SSL_clear) RESOLVEFUNC(SSL_connect) diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index 4cad0231cd..be67f38b64 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -352,6 +352,14 @@ int q_SSL_CTX_use_PrivateKey(SSL_CTX *a, EVP_PKEY *b); int q_SSL_CTX_use_RSAPrivateKey(SSL_CTX *a, RSA *b); int q_SSL_CTX_use_PrivateKey_file(SSL_CTX *a, const char *b, int c); X509_STORE *q_SSL_CTX_get_cert_store(const SSL_CTX *a); +#if OPENSSL_VERSION_NUMBER >= 0x10002000L +SSL_CONF_CTX *q_SSL_CONF_CTX_new(); +void q_SSL_CONF_CTX_free(SSL_CONF_CTX *a); +void q_SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *a, SSL_CTX *b); +unsigned int q_SSL_CONF_CTX_set_flags(SSL_CONF_CTX *a, unsigned int b); +int q_SSL_CONF_CTX_finish(SSL_CONF_CTX *a); +int q_SSL_CONF_cmd(SSL_CONF_CTX *a, const char *b, const char *c); +#endif void q_SSL_free(SSL *a); STACK_OF(SSL_CIPHER) *q_SSL_get_ciphers(const SSL *a); #if OPENSSL_VERSION_NUMBER >= 0x10000000L diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp index a936ec7aad..580cf0e31d 100644 --- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp +++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp @@ -1601,7 +1601,13 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt int x = message.arguments().at(0).toInt(); int y = message.arguments().at(1).toInt(); uint coordType = message.arguments().at(2).toUInt(); - Q_UNUSED (coordType) // FIXME + if (coordType == ATSPI_COORD_TYPE_WINDOW) { + QWindow * window = interface->window(); + if (window) { + x += window->position().x(); + y += window->position().y(); + } + } QAccessibleInterface * childInterface(interface->childAt(x, y)); QAccessibleInterface * iface = 0; diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 7ea3d130f7..98b9f7c9ba 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -198,7 +198,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate); static QString strippedText(QString s) { - s.remove( QString::fromLatin1("...") ); + s.remove(QLatin1String("...")); return QPlatformTheme::removeMnemonics(s).trimmed(); } diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index de2c30cdfb..a6f6a7aac9 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -228,7 +228,7 @@ extern "C" int qt_main_wrapper(int argc, char *argv[]) } } - qEventDispatcherDebug() << "Running UIApplicationMain"; qIndent(); + qCDebug(lcEventDispatcher) << "Running UIApplicationMain"; return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSApplicationDelegate class])); } } @@ -263,7 +263,7 @@ static void __attribute__((noinline, noreturn)) user_main_trampoline() int exitCode = main(argc, argv); delete[] argv; - qEventDispatcherDebug() << "Returned from main with exit code " << exitCode; + qCDebug(lcEventDispatcher) << "Returned from main with exit code " << exitCode; if (Q_UNLIKELY(debugStackUsage)) userMainStack.printUsage(); @@ -322,7 +322,7 @@ static bool rootLevelRunLoopIntegration() + (void)applicationDidFinishLaunching:(NSNotification *)notification { - qCDebug(lcQpaApplication) << "Application launched with options" << notification.userInfo; + qCDebug(lcEventDispatcher) << "Application launched with options" << notification.userInfo; if (!isQtApplication()) return; @@ -331,7 +331,7 @@ static bool rootLevelRunLoopIntegration() // We schedule the main-redirection for the next run-loop pass, so that we // can return from this function and let UIApplicationMain finish its job. // This results in running Qt's application eventloop as a nested runloop. - qCDebug(lcQpaApplication) << "Scheduling main() on next run-loop pass"; + qCDebug(lcEventDispatcher) << "Scheduling main() on next run-loop pass"; CFRunLoopTimerRef userMainTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 0, 0, 0, ^(CFRunLoopTimerRef) { user_main_trampoline(); }); CFRunLoopAddTimer(CFRunLoopGetMain(), userMainTimer, kCFRunLoopCommonModes); @@ -339,10 +339,10 @@ static bool rootLevelRunLoopIntegration() return; } + switch (setjmp(processEventEnterJumpPoint)) { case kJumpPointSetSuccessfully: - qCDebug(lcQpaApplication) << "Running main() on separate stack"; qIndent(); - + qCDebug(lcEventDispatcher) << "Running main() on separate stack"; // Redirect the stack pointer to the start of the reserved stack. This ensures // that when we longjmp out of the event dispatcher and continue execution, the // 'Qt main' call-stack will not be smashed, as it lives in a part of the stack @@ -360,7 +360,7 @@ static bool rootLevelRunLoopIntegration() case kJumpedFromEventDispatcherProcessEvents: // We've returned from the longjmp in the event dispatcher, // and the stack has been restored to its old self. - qUnIndent(); qCDebug(lcQpaApplication) << "Returned from processEvents"; + qCDebug(lcEventDispatcher) << "↳ Jumped from processEvents due to exec"; if (Q_UNLIKELY(debugStackUsage)) userMainStack.printUsage(); @@ -396,18 +396,18 @@ static const char kApplicationWillTerminateExitCode = char(SIGTERM | 0x80); applicationAboutToTerminate = true; switch (setjmp(applicationWillTerminateJumpPoint)) { case kJumpPointSetSuccessfully: - qEventDispatcherDebug() << "Exiting qApp with SIGTERM exit code"; qIndent(); + qCDebug(lcEventDispatcher) << "Exiting qApp with SIGTERM exit code"; qApp->exit(kApplicationWillTerminateExitCode); // The runloop will not exit when the application is about to terminate, // so we'll never see the exit activity and have a chance to return from // QEventLoop::exec(). We initiate the return manually as a workaround. - qEventDispatcherDebug() << "Manually triggering return from event loop exec"; + qCDebug(lcEventDispatcher) << "Manually triggering return from event loop exec"; static_cast<QIOSEventDispatcher *>(qApp->eventDispatcher())->interruptEventLoopExec(); break; case kJumpedFromUserMainTrampoline: // The user's main has returned, so we're ready to let iOS terminate the application - qUnIndent(); qEventDispatcherDebug() << "kJumpedFromUserMainTrampoline, allowing iOS to terminate"; + qCDebug(lcEventDispatcher) << "kJumpedFromUserMainTrampoline, allowing iOS to terminate"; break; default: qFatal("Unexpected jump result in event loop integration"); @@ -434,13 +434,15 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo return QEventDispatcherCoreFoundation::processEvents(flags); if (applicationAboutToTerminate) { - qEventDispatcherDebug() << "Detected QEventLoop exec after application termination"; + qCDebug(lcEventDispatcher) << "Detected QEventLoop exec after application termination"; // Re-issue exit, and return immediately qApp->exit(kApplicationWillTerminateExitCode); return false; } if (!m_processEventLevel && (flags & QEventLoop::EventLoopExec)) { + qCDebug(lcEventDispatcher) << "Processing events with flags" << flags; + ++m_processEventLevel; m_runLoopExitObserver.addToMode(kCFRunLoopCommonModes); @@ -449,7 +451,7 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo // is asked to exit, so that we can return from QEventLoop::exec(). switch (setjmp(processEventExitJumpPoint)) { case kJumpPointSetSuccessfully: - qEventDispatcherDebug() << "QEventLoop exec detected, jumping back to native runloop"; + qCDebug(lcEventDispatcher) << "QEventLoop exec detected, jumping back to system runloop ↵"; longjmp(processEventEnterJumpPoint, kJumpedFromEventDispatcherProcessEvents); break; case kJumpedFromEventLoopExecInterrupt: @@ -457,7 +459,7 @@ bool __attribute__((returns_twice)) QIOSEventDispatcher::processEvents(QEventLoo // signal), and we jumped back though processEventExitJumpPoint. We return from processEvents, // which will emit aboutToQuit if it's QApplication's event loop, and then return to the user's // main, which can do whatever it wants, including calling exec() on the application again. - qEventDispatcherDebug() << "kJumpedFromEventLoopExecInterrupt, returning with eventsProcessed = true"; + qCDebug(lcEventDispatcher) << "⇢ System runloop exited, returning with eventsProcessed = true"; return true; default: qFatal("Unexpected jump result in event loop integration"); @@ -485,9 +487,8 @@ bool QIOSEventDispatcher::processPostedEvents() if (!QEventDispatcherCoreFoundation::processPostedEvents()) return false; - qEventDispatcherDebug() << "Sending window system events for " << m_processEvents.flags; qIndent(); + qCDebug(lcEventDispatcher) << "Sending window system events for" << m_processEvents.flags; QWindowSystemInterface::sendWindowSystemEvents(m_processEvents.flags); - qUnIndent(); return true; } @@ -497,10 +498,8 @@ void QIOSEventDispatcher::handleRunLoopExit(CFRunLoopActivity activity) Q_UNUSED(activity); Q_ASSERT(activity == kCFRunLoopExit); - if (m_processEventLevel == 1 && !currentEventLoop()->isRunning()) { - qEventDispatcherDebug() << "Root runloop level exited"; + if (m_processEventLevel == 1 && !currentEventLoop()->isRunning()) interruptEventLoopExec(); - } } void QIOSEventDispatcher::interruptEventLoopExec() @@ -516,12 +515,12 @@ void QIOSEventDispatcher::interruptEventLoopExec() // processEvents, instead of back in didFinishLaunchingWithOptions. switch (setjmp(processEventEnterJumpPoint)) { case kJumpPointSetSuccessfully: - qEventDispatcherDebug() << "Jumping back to processEvents"; + qCDebug(lcEventDispatcher) << "Jumping into processEvents due to system runloop exit ⇢"; longjmp(processEventExitJumpPoint, kJumpedFromEventLoopExecInterrupt); break; case kJumpedFromEventDispatcherProcessEvents: // QEventLoop was re-executed - qEventDispatcherDebug() << "kJumpedFromEventDispatcherProcessEvents"; + qCDebug(lcEventDispatcher) << "↳ Jumped from processEvents due to re-exec"; break; default: qFatal("Unexpected jump result in event loop integration"); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index d989761297..22d90d6ac2 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -673,4 +673,60 @@ void *QXcbNativeInterface::handlerNativeResourceForBackingStore(const QByteArray return nullptr; } +static void dumpNativeWindowsRecursion(const QXcbConnection *connection, xcb_window_t window, + int level, QTextStream &str) +{ + if (level) + str << QByteArray(2 * level, ' '); + + xcb_connection_t *conn = connection->xcb_connection(); + auto geomReply = Q_XCB_REPLY(xcb_get_geometry, conn, window); + if (!geomReply) + return; + const QRect geom(geomReply->x, geomReply->y, geomReply->width, geomReply->height); + if (!geom.isValid() || (geom.width() <= 3 && geom.height() <= 3)) + return; // Skip helper/dummy windows. + str << "0x"; + const int oldFieldWidth = str.fieldWidth(); + const QChar oldPadChar =str.padChar(); + str.setFieldWidth(8); + str.setPadChar(QLatin1Char('0')); + str << hex << window; + str.setFieldWidth(oldFieldWidth); + str.setPadChar(oldPadChar); + str << dec << " \"" + << QXcbWindow::windowTitle(connection, window) << "\" " + << geom.width() << 'x' << geom.height() << forcesign << geom.x() << geom.y() + << noforcesign << '\n'; + + auto reply = Q_XCB_REPLY(xcb_query_tree, conn, window); + if (reply) { + const int count = xcb_query_tree_children_length(reply.get()); + const xcb_window_t *children = xcb_query_tree_children(reply.get()); + for (int i = 0; i < count; ++i) + dumpNativeWindowsRecursion(connection, children[i], level + 1, str); + } +} + +QString QXcbNativeInterface::dumpConnectionNativeWindows(const QXcbConnection *connection, WId root) const +{ + QString result; + QTextStream str(&result); + if (root) { + dumpNativeWindowsRecursion(connection, xcb_window_t(root), 0, str); + } else { + for (const QXcbScreen *screen : connection->screens()) { + str << "Screen: \"" << screen->name() << "\"\n"; + dumpNativeWindowsRecursion(connection, screen->root(), 0, str); + str << '\n'; + } + } + return result; +} + +QString QXcbNativeInterface::dumpNativeWindows(WId root) const +{ + return dumpConnectionNativeWindows(QXcbIntegration::instance()->defaultConnection(), root); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index fb0db727aa..6a752c68ca 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -127,6 +127,8 @@ public: Q_INVOKABLE bool systrayVisualHasAlphaChannel(); Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window); Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window); + Q_INVOKABLE QString dumpConnectionNativeWindows(const QXcbConnection *connection, WId root) const; + Q_INVOKABLE QString dumpNativeWindows(WId root = 0) const; void addHandler(QXcbNativeInterfaceHandler *handler); void removeHandler(QXcbNativeInterfaceHandler *handler); diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index e3d9bc7a3d..49bf5181cc 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -91,16 +91,8 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) { xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply.get())); - if (windowManager != XCB_WINDOW_NONE) { - auto windowManagerReply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), - false, windowManager, - atom(QXcbAtom::_NET_WM_NAME), - atom(QXcbAtom::UTF8_STRING), 0, 1024); - if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) { - m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply.get()), - xcb_get_property_value_length(windowManagerReply.get())); - } - } + if (windowManager != XCB_WINDOW_NONE) + m_windowManagerName = QXcbWindow::windowTitle(connection, windowManager); } const xcb_query_extension_reply_t *sync_reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 44b337f555..5b05a230e4 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2849,5 +2849,18 @@ QXcbScreen *QXcbWindow::xcbScreen() const return static_cast<QXcbScreen *>(screen()); } +QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window) +{ + const xcb_atom_t utf8Atom = conn->atom(QXcbAtom::UTF8_STRING); + auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, conn->xcb_connection(), + false, window, conn->atom(QXcbAtom::_NET_WM_NAME), + utf8Atom, 0, 1024); + if (reply && reply->format == 8 && reply->type == utf8Atom) { + const char *name = reinterpret_cast<const char *>(xcb_get_property_value(reply.get())); + return QString::fromUtf8(name); + } + return QString(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index f506d7dd6f..957c4e9cbd 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -184,6 +184,8 @@ public: virtual void create(); virtual void destroy(); + static QString windowTitle(const QXcbConnection *conn, xcb_window_t window); + public Q_SLOTS: void updateSyncRequestCounter(); diff --git a/src/plugins/platformthemes/flatpak/qflatpakfiledialog.cpp b/src/plugins/platformthemes/flatpak/qflatpakfiledialog.cpp index c51223186e..1a24015ce5 100644 --- a/src/plugins/platformthemes/flatpak/qflatpakfiledialog.cpp +++ b/src/plugins/platformthemes/flatpak/qflatpakfiledialog.cpp @@ -147,61 +147,7 @@ void QFlatpakFileDialog::initializeDialog() setDirectory(options()->initialDirectory()); } -bool QFlatpakFileDialog::defaultNameFilterDisables() const -{ - return false; -} - -void QFlatpakFileDialog::setDirectory(const QUrl &directory) -{ - Q_D(QFlatpakFileDialog); - - d->directory = directory.path(); -} - -QUrl QFlatpakFileDialog::directory() const -{ - Q_D(const QFlatpakFileDialog); - - return d->directory; -} - -void QFlatpakFileDialog::selectFile(const QUrl &filename) -{ - Q_D(QFlatpakFileDialog); - - d->selectedFiles << filename.path(); -} - -QList<QUrl> QFlatpakFileDialog::selectedFiles() const -{ - Q_D(const QFlatpakFileDialog); - - QList<QUrl> files; - for (const QString &file : d->selectedFiles) { - files << QUrl(file); - } - return files; -} - -void QFlatpakFileDialog::setFilter() -{ - // TODO -} - -void QFlatpakFileDialog::selectNameFilter(const QString &filter) -{ - Q_UNUSED(filter); - // TODO -} - -QString QFlatpakFileDialog::selectedNameFilter() const -{ - // TODO - return QString(); -} - -void QFlatpakFileDialog::exec() +void QFlatpakFileDialog::openPortal() { Q_D(const QFlatpakFileDialog); @@ -305,7 +251,64 @@ void QFlatpakFileDialog::exec() SLOT(gotResponse(uint,QVariantMap))); } }); +} +bool QFlatpakFileDialog::defaultNameFilterDisables() const +{ + return false; +} + +void QFlatpakFileDialog::setDirectory(const QUrl &directory) +{ + Q_D(QFlatpakFileDialog); + + d->directory = directory.path(); +} + +QUrl QFlatpakFileDialog::directory() const +{ + Q_D(const QFlatpakFileDialog); + + return d->directory; +} + +void QFlatpakFileDialog::selectFile(const QUrl &filename) +{ + Q_D(QFlatpakFileDialog); + + d->selectedFiles << filename.path(); +} + +QList<QUrl> QFlatpakFileDialog::selectedFiles() const +{ + Q_D(const QFlatpakFileDialog); + + QList<QUrl> files; + for (const QString &file : d->selectedFiles) { + files << QUrl(file); + } + return files; +} + +void QFlatpakFileDialog::setFilter() +{ + // TODO +} + +void QFlatpakFileDialog::selectNameFilter(const QString &filter) +{ + Q_UNUSED(filter); + // TODO +} + +QString QFlatpakFileDialog::selectedNameFilter() const +{ + // TODO + return QString(); +} + +void QFlatpakFileDialog::exec() +{ // HACK we have to avoid returning until we emit that the dialog was accepted or rejected QEventLoop loop; loop.connect(this, SIGNAL(accept()), SLOT(quit())); @@ -327,6 +330,8 @@ bool QFlatpakFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality wi d->modal = windowModality != Qt::NonModal; d->winId = parent ? parent->winId() : 0; + openPortal(); + return true; } diff --git a/src/plugins/platformthemes/flatpak/qflatpakfiledialog_p.h b/src/plugins/platformthemes/flatpak/qflatpakfiledialog_p.h index 8f65d07e62..f3e195faa0 100644 --- a/src/plugins/platformthemes/flatpak/qflatpakfiledialog_p.h +++ b/src/plugins/platformthemes/flatpak/qflatpakfiledialog_p.h @@ -90,6 +90,7 @@ private Q_SLOTS: private: void initializeDialog(); + void openPortal(); QScopedPointer<QFlatpakFileDialogPrivate> d_ptr; }; diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp index 763f676e41..bd0d641e79 100644 --- a/src/plugins/printsupport/cups/qcupsprintengine.cpp +++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp @@ -250,38 +250,6 @@ void QCupsPrintEnginePrivate::closePrintDevice() } } -void QCupsPrintEnginePrivate::setupDefaultPrinter() -{ - // Should never have reached here if no plugin available, but check just in case - QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get(); - if (!ps) - return; - - // Get default printer id, if no default then use the first available - // TODO Find way to remove printerName from base class? - printerName = ps->defaultPrintDeviceId(); - if (printerName.isEmpty()) { - QStringList list = ps->availablePrintDeviceIds(); - if (list.size() > 0) - printerName = list.at(0); - } - - // Should never have reached here if no printers available, but check just in case - if (printerName.isEmpty()) - return; - - m_printDevice = ps->createPrintDevice(printerName); - if (!m_printDevice.isValid()) - return; - - // Setup the printer defaults - duplex = m_printDevice.defaultDuplexMode(); - grayscale = m_printDevice.defaultColorMode() == QPrint::GrayScale; - // CUPS server always supports collation, even if individual m_printDevice doesn't - collate = true; - setPageSize(m_printDevice.defaultPageSize()); -} - void QCupsPrintEnginePrivate::changePrinter(const QString &newPrinter) { // Don't waste time if same printer name diff --git a/src/plugins/printsupport/cups/qcupsprintengine_p.h b/src/plugins/printsupport/cups/qcupsprintengine_p.h index c99c48c7ea..d5363bb8cc 100644 --- a/src/plugins/printsupport/cups/qcupsprintengine_p.h +++ b/src/plugins/printsupport/cups/qcupsprintengine_p.h @@ -93,7 +93,6 @@ public: private: Q_DISABLE_COPY(QCupsPrintEnginePrivate) - void setupDefaultPrinter(); void changePrinter(const QString &newPrinter); void setPageSize(const QPageSize &pageSize); diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 1041187407..10fe3f6f0e 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -237,6 +237,19 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QIndeterminateProgressIndicator); @end +@interface QT_MANGLE_NAMESPACE(QVerticalSplitView) : NSSplitView +- (BOOL)isVertical; +@end + +QT_NAMESPACE_ALIAS_OBJC_CLASS(QVerticalSplitView); + +@implementation QVerticalSplitView +- (BOOL)isVertical +{ + return YES; +} +@end + QT_BEGIN_NAMESPACE // The following constants are used for adjusting the size @@ -2002,6 +2015,15 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const // at construction time, and it cannot be changed later. bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)]; break; + case SplitView_Horizontal: + bv = [[NSSplitView alloc] init]; + break; + case SplitView_Vertical: + bv = [[QVerticalSplitView alloc] init]; + break; + case TextField: + bv = [[NSTextField alloc] init]; + break; default: break; } @@ -2076,7 +2098,7 @@ NSCell *QMacStylePrivate::cocoaCell(CocoaControl widget) const return cell; } -void QMacStylePrivate::drawNSViewInRect(CocoaControl widget, NSView *view, const QRect &qtRect, QPainter *p, bool isQWidget, DrawRectBlock drawRectBlock) const +void QMacStylePrivate::drawNSViewInRect(CocoaControl widget, NSView *view, const QRect &qtRect, QPainter *p, bool isQWidget, __attribute__((noescape)) DrawRectBlock drawRectBlock) const { QPoint offset; if (widget == CocoaControl(Button_PopupButton, QStyleHelper::SizeSmall)) @@ -3444,35 +3466,21 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai case PE_FrameLineEdit: if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { if (frame->state & State_Sunken) { - QColor baseColor(frame->palette.background().color()); - HIThemeFrameDrawInfo fdi; - fdi.version = qt_mac_hitheme_version; - fdi.state = tds; - int frame_size; - fdi.kind = frame->features & QStyleOptionFrame::Rounded ? kHIThemeFrameTextFieldRound : - kHIThemeFrameTextFieldSquare; - frame_size = qt_mac_aqua_get_metric(EditTextFrameOutset); - if ((frame->state & State_ReadOnly) || !(frame->state & State_Enabled)) - fdi.state = kThemeStateInactive; - else if (fdi.state == kThemeStatePressed) - // This pressed state doesn't make sense for a line edit frame. - // And Yosemite agrees with us. Otherwise it starts showing yellow pixels. - fdi.state = kThemeStateActive; - fdi.isFocused = (frame->state & State_HasFocus); - int lw = frame->lineWidth; - if (lw <= 0) - lw = proxy()->pixelMetric(PM_DefaultFrameWidth, frame, w); - { //clear to base color - p->save(); - p->setPen(QPen(baseColor, lw)); - p->setBrush(Qt::NoBrush); - p->drawRect(frame->rect); - p->restore(); - } - const auto frameMargins = QMargins(frame_size, frame_size, frame_size, frame_size); - const CGRect cgRect = frame->rect.marginsRemoved(frameMargins).toCGRect(); - - HIThemeDrawFrame(&cgRect, &fdi, cg, kHIThemeOrientationNormal); + const bool isEnabled = opt->state & State_Enabled; + const bool isReadOnly = opt->state & State_ReadOnly; + const bool isRounded = frame->features & QStyleOptionFrame::Rounded; + const auto cs = d->effectiveAquaSizeConstrain(opt, w, CT_LineEdit); + const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::TextField, cs); + auto *tf = static_cast<NSTextField *>(d->cocoaControl(cw)); + tf.enabled = isEnabled; + tf.editable = !isReadOnly; + tf.bezeled = YES; + static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel; + tf.frame = opt->rect.toCGRect(); + d->drawNSViewInRect(cw, tf, opt->rect, p, w != nullptr, ^(CGContextRef ctx, const CGRect &rect) { + Q_UNUSED(ctx); + [tf.cell drawWithFrame:rect inView:tf]; + }); } else { QCommonStyle::drawPrimitive(pe, opt, p, w); } @@ -4498,13 +4506,16 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter break; } case CE_Splitter: - if (opt->rect.width() > 1 && opt->rect.height() > 1){ - HIThemeSplitterDrawInfo sdi; - sdi.version = qt_mac_hitheme_version; - sdi.state = tds; - sdi.adornment = kHIThemeSplitterAdornmentMetal; - CGRect cgRect = opt->rect.toCGRect(); - HIThemeDrawPaneSplitter(&cgRect, &sdi, cg, kHIThemeOrientationNormal); + if (opt->rect.width() > 1 && opt->rect.height() > 1) { + const bool isVertical = !(opt->state & QStyle::State_Horizontal); + // Qt refers to the layout orientation, while Cocoa refers to the divider's. + const auto ct = isVertical ? QMacStylePrivate::SplitView_Horizontal : QMacStylePrivate::SplitView_Vertical; + const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge); + auto *sv = static_cast<NSSplitView *>(d->cocoaControl(cw)); + sv.frame = opt->rect.toCGRect(); + d->drawNSViewInRect(cw, sv, opt->rect, p, w != nullptr, ^(CGContextRef ctx, const CGRect &rect) { + [sv drawDividerInRect:rect]; + }); } else { QPen oldPen = p->pen(); p->setPen(opt->palette.dark().color()); diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index cf2609e9ec..00dc8a9b53 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -200,7 +200,10 @@ public: Scroller_Vertical, Slider_Horizontal, Slider_Vertical, - Stepper // QSpinBox buttons + SplitView_Horizontal, + SplitView_Vertical, + Stepper, // QSpinBox buttons + TextField }; typedef QPair<CocoaControlType, QStyleHelper::WidgetSizePolicy> CocoaControl; @@ -270,7 +273,7 @@ public: void setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const; - void drawNSViewInRect(CocoaControl widget, NSView *view, const QRect &rect, QPainter *p, bool isQWidget = true, DrawRectBlock drawRectBlock = nil) const; + void drawNSViewInRect(CocoaControl widget, NSView *view, const QRect &rect, QPainter *p, bool isQWidget = true, __attribute__((noescape)) DrawRectBlock drawRectBlock = nil) const; void resolveCurrentNSView(QWindow *window) const; void drawFocusRing(QPainter *p, const QRect &targetRect, int hMargin, int vMargin, qreal radius = 0) const; diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp index 078875033f..6add110249 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp @@ -990,7 +990,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption XPThemeData theme(widget, 0, QWindowsXPStylePrivate::ToolBarTheme, TP_DROPDOWNBUTTON); if (theme.isValid()) { - const QSizeF size = theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget); + const QSizeF size = theme.size() * QStyleHelper::dpiScaled(1); if (!size.isEmpty()) { mbiw = qRound(size.width()); mbih = qRound(size.height()); @@ -1513,7 +1513,7 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle if (d->transitionsEnabled() && canAnimate(option)) { - if (control == CC_ScrollBar || control == CC_SpinBox ) { + if (control == CC_ScrollBar || control == CC_SpinBox || control == CC_ComboBox) { QObject *styleObject = option->styleObject; // Can be widget or qquickitem @@ -1643,12 +1643,28 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle } else { if (sub & SC_ComboBoxFrame) { - QStyleOptionButton btn; - btn.QStyleOption::operator=(*option); - btn.rect = option->rect.adjusted(-1, -1, 1, 1); - if (sub & SC_ComboBoxArrow) - btn.features = QStyleOptionButton::HasMenu; - proxy()->drawControl(QStyle::CE_PushButton, &btn, painter, widget); + XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme); + theme.rect = option->rect; + theme.partId = CP_READONLY; + if (!(cmb->state & State_Enabled)) + theme.stateId = CBXS_DISABLED; + else if (cmb->state & State_Sunken || cmb->state & State_On) + theme.stateId = CBXS_PRESSED; + else if (cmb->state & State_MouseOver) + theme.stateId = CBXS_HOT; + else + theme.stateId = CBXS_NORMAL; + d->drawBackground(theme); + } + if (sub & SC_ComboBoxArrow) { + XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme); + theme.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget); + theme.partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT; + if (!(cmb->state & State_Enabled)) + theme.stateId = CBXS_DISABLED; + else + theme.stateId = CBXS_NORMAL; + d->drawBackground(theme); } } } @@ -2123,15 +2139,12 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt #if QT_CONFIG(combobox) case CC_ComboBox: if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { - int x = cb->rect.x(), - y = cb->rect.y(), - wi = cb->rect.width(), - he = cb->rect.height(); - int xpos = x; - int margin = cb->frame ? 3 : 0; - int bmarg = cb->frame ? 2 : 0; - int arrowButtonWidth = bmarg + 16; - xpos += wi - arrowButtonWidth; + const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height(); + const int margin = cb->frame ? 3 : 0; + const int bmarg = cb->frame ? 2 : 0; + const int arrowWidth = qRound(QStyleHelper::dpiScaled(16)); + const int arrowButtonWidth = bmarg + arrowWidth; + const int xpos = x + wi - arrowButtonWidth; switch (subControl) { case SC_ComboBoxFrame: @@ -2141,7 +2154,7 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt rect.setRect(xpos, y , arrowButtonWidth, he); break; case SC_ComboBoxEditField: - rect.setRect(x + margin, y + margin, wi - 2 * margin - 16, he - 2 * margin); + rect.setRect(x + margin, y + margin, wi - 2 * margin - arrowWidth, he - 2 * margin); break; case SC_ComboBoxListBoxPopup: rect = cb->rect; diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index cf344c8f88..ff27cab98a 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -887,6 +887,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa PROPERTYORIGIN origin = PO_NOTFOUND; GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin); GetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize); + borderSize *= additionalDevicePixelRatio; // Clip away border region if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) { @@ -996,7 +997,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa } if (addBorderContentClipping) - painter->setClipRegion(extraClip, Qt::IntersectClip); + painter->setClipRegion(scaleRegion(extraClip, 1.0 / additionalDevicePixelRatio), Qt::IntersectClip); if (!themeData.mirrorHorizontally && !themeData.mirrorVertically && !themeData.rotate) { if (!haveCachedPixmap) @@ -1479,11 +1480,12 @@ case PE_Frame: // GetThemeInt(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &borderSize); // Inner white border - p->setPen(QPen(option->palette.base().color(), 1)); - p->drawRect(option->rect.adjusted(1, 1, -2, -2)); + p->setPen(QPen(option->palette.base().color(), 0)); + p->drawRect(QRectF(option->rect).adjusted(QStyleHelper::dpiScaled(0.5), QStyleHelper::dpiScaled(0.5), + QStyleHelper::dpiScaled(-1), QStyleHelper::dpiScaled(-1))); // Outer dark border - p->setPen(QPen(bordercolor, 1)); - p->drawRect(option->rect.adjusted(0, 0, -1, -1)); + p->setPen(QPen(bordercolor, 0)); + p->drawRect(QRectF(option->rect).adjusted(0, 0, QStyleHelper::dpiScaled(-0.5), QStyleHelper::dpiScaled(-0.5))); p->setPen(oldPen); return; } else if (fillType == BT_NONE) { @@ -3511,9 +3513,8 @@ QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionCompl case CC_ComboBox: if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { - int x = cmb->rect.x(), y = cmb->rect.y(), wi = cmb->rect.width(), he = cmb->rect.height(); - int xpos = x; - xpos += wi - 1 - 16; + const int x = cmb->rect.x(), y = cmb->rect.y(), wi = cmb->rect.width(), he = cmb->rect.height(); + const int xpos = x + wi - qRound(QStyleHelper::dpiScaled(1 + 16)); switch (subControl) { case SC_ComboBoxFrame: @@ -3521,11 +3522,13 @@ QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionCompl break; case SC_ComboBoxArrow: - rect = QRect(xpos, y+1, 16, he-2); + rect = QRect(xpos, y + qRound(QStyleHelper::dpiScaled(1)), + qRound(QStyleHelper::dpiScaled(16)), he - qRound(QStyleHelper::dpiScaled(2))); break; case SC_ComboBoxEditField: - rect = QRect(x+2, y+2, wi-3-16, he-4); + rect = QRect(x + qRound(QStyleHelper::dpiScaled(2)), y + qRound(QStyleHelper::dpiScaled(2)), + wi - qRound(QStyleHelper::dpiScaled(3 + 16)), he - qRound(QStyleHelper::dpiScaled(4))); break; case SC_ComboBoxListBoxPopup: diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp index 2cc5bfbb8c..caab7867dc 100644 --- a/src/printsupport/dialogs/qprintdialog_unix.cpp +++ b/src/printsupport/dialogs/qprintdialog_unix.cpp @@ -403,6 +403,10 @@ QPrintPropertiesDialog::~QPrintPropertiesDialog() void QPrintPropertiesDialog::setupPrinter() const { +#if QT_CONFIG(cups) + QCUPSSupport::clearCupsOptions(m_printer); +#endif + widget.pageSetup->setupPrinter(); #if QT_CONFIG(cupsjobwidget) m_jobOptions->setupPrinter(); diff --git a/src/printsupport/kernel/qcups.cpp b/src/printsupport/kernel/qcups.cpp index be170ed619..7e8e1707b2 100644 --- a/src/printsupport/kernel/qcups.cpp +++ b/src/printsupport/kernel/qcups.cpp @@ -77,6 +77,11 @@ void QCUPSSupport::clearCupsOption(QPrinter *printer, const QString &option) } } +void QCUPSSupport::clearCupsOptions(QPrinter *printer) +{ + setCupsOptions(printer, QStringList()); +} + static inline QString jobHoldToString(const QCUPSSupport::JobHoldUntil jobHold, const QTime holdUntilTime) { switch (jobHold) { diff --git a/src/printsupport/kernel/qcups_p.h b/src/printsupport/kernel/qcups_p.h index da2b087d5b..9a71483bb9 100644 --- a/src/printsupport/kernel/qcups_p.h +++ b/src/printsupport/kernel/qcups_p.h @@ -132,6 +132,7 @@ public: static void setCupsOption(QPrinter *printer, const QString &option, const QString &value); static void clearCupsOption(QPrinter *printer, const QString &option); + static void clearCupsOptions(QPrinter *printer); static void setJobHold(QPrinter *printer, const JobHoldUntil jobHold = NoHold, const QTime &holdUntilTime = QTime()); static void setJobBilling(QPrinter *printer, const QString &jobBilling = QString()); diff --git a/src/printsupport/kernel/qplatformprintersupport.cpp b/src/printsupport/kernel/qplatformprintersupport.cpp index e12a292aec..a25dc6d45c 100644 --- a/src/printsupport/kernel/qplatformprintersupport.cpp +++ b/src/printsupport/kernel/qplatformprintersupport.cpp @@ -89,11 +89,6 @@ QPrintDevice QPlatformPrinterSupport::createPrintDevice(const QString &id) return QPrintDevice(); } -QPrintDevice QPlatformPrinterSupport::createDefaultPrintDevice() -{ - return createPrintDevice(defaultPrintDeviceId()); -} - QStringList QPlatformPrinterSupport::availablePrintDeviceIds() const { return QStringList(); diff --git a/src/printsupport/kernel/qplatformprintersupport.h b/src/printsupport/kernel/qplatformprintersupport.h index 6a4246adc0..413c1067c2 100644 --- a/src/printsupport/kernel/qplatformprintersupport.h +++ b/src/printsupport/kernel/qplatformprintersupport.h @@ -76,7 +76,6 @@ public: virtual QPaintEngine *createPaintEngine(QPrintEngine *, QPrinter::PrinterMode printerMode); virtual QPrintDevice createPrintDevice(const QString &id); - virtual QPrintDevice createDefaultPrintDevice(); virtual QStringList availablePrintDeviceIds() const; virtual QString defaultPrintDeviceId() const; diff --git a/src/src.pro b/src/src.pro index a2064b1362..3b93b1a9d8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -QT_FOR_CONFIG += gui-private +QT_FOR_CONFIG += core-private gui-private include($$OUT_PWD/corelib/qtcore-config.pri) include($$OUT_PWD/gui/qtgui-config.pri) @@ -30,6 +30,10 @@ src_tools_qlalr.target = sub-qlalr force_bootstrap: src_tools_qlalr.depends = src_tools_bootstrap else: src_tools_qlalr.depends = src_corelib +src_tools_tracegen.subdir = tools/tracegen +src_tools_tracegen.target = sub-tracegen +src_tools_tracegen.depends = src_tools_bootstrap + src_tools_uic.subdir = tools/uic src_tools_uic.target = sub-uic force_bootstrap: src_tools_uic.depends = src_tools_bootstrap @@ -152,8 +156,13 @@ qtConfig(regularexpression):pcre2 { SUBDIRS += src_3rdparty_pcre2 src_corelib.depends += src_3rdparty_pcre2 } -SUBDIRS += src_corelib src_tools_qlalr TOOLS = src_tools_moc src_tools_rcc src_tools_qlalr src_tools_qfloat16_tables +!force_bootstrap:if(qtConfig(lttng)|qtConfig(etw)) { + SUBDIRS += src_tools_tracegen + src_corelib.depends += src_tools_tracegen + TOOLS += src_tools_tracegen +} +SUBDIRS += src_corelib src_tools_qlalr win32:SUBDIRS += src_winmain qtConfig(network) { SUBDIRS += src_network @@ -220,7 +229,8 @@ android: SUBDIRS += src_android src_3rdparty_gradle TR_EXCLUDE = \ src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_uic src_tools_qlalr \ src_tools_bootstrap_dbus src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml \ - src_3rdparty_pcre2 src_3rdparty_harfbuzzng src_3rdparty_freetype + src_3rdparty_pcre2 src_3rdparty_harfbuzzng src_3rdparty_freetype \ + src_tools_tracegen sub-tools.depends = $$TOOLS QMAKE_EXTRA_TARGETS = sub-tools diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro index a88333f03a..a45382106a 100644 --- a/src/tools/bootstrap/bootstrap.pro +++ b/src/tools/bootstrap/bootstrap.pro @@ -32,7 +32,6 @@ SOURCES += \ ../../corelib/global/qrandom.cpp \ ../../corelib/io/qabstractfileengine.cpp \ ../../corelib/io/qbuffer.cpp \ - ../../corelib/io/qdatastream.cpp \ ../../corelib/io/qdebug.cpp \ ../../corelib/io/qdir.cpp \ ../../corelib/io/qdiriterator.cpp \ @@ -47,7 +46,6 @@ SOURCES += \ ../../corelib/io/qresource.cpp \ ../../corelib/io/qtemporarydir.cpp \ ../../corelib/io/qtemporaryfile.cpp \ - ../../corelib/io/qtextstream.cpp \ ../../corelib/io/qsavefile.cpp \ ../../corelib/io/qstandardpaths.cpp \ ../../corelib/io/qloggingcategory.cpp \ @@ -58,6 +56,17 @@ SOURCES += \ ../../corelib/kernel/qvariant.cpp \ ../../corelib/kernel/qsystemerror.cpp \ ../../corelib/plugin/quuid.cpp \ + ../../corelib/serialization/qdatastream.cpp \ + ../../corelib/serialization/qjson.cpp \ + ../../corelib/serialization/qjsondocument.cpp \ + ../../corelib/serialization/qjsonobject.cpp \ + ../../corelib/serialization/qjsonarray.cpp \ + ../../corelib/serialization/qjsonvalue.cpp \ + ../../corelib/serialization/qjsonparser.cpp \ + ../../corelib/serialization/qjsonwriter.cpp \ + ../../corelib/serialization/qtextstream.cpp \ + ../../corelib/serialization/qxmlutils.cpp \ + ../../corelib/serialization/qxmlstream.cpp \ ../../corelib/tools/qbitarray.cpp \ ../../corelib/tools/qbytearray.cpp \ ../../corelib/tools/qarraydata.cpp \ @@ -84,15 +93,6 @@ SOURCES += \ ../../corelib/tools/qstringlist.cpp \ ../../corelib/tools/qversionnumber.cpp \ ../../corelib/tools/qvsnprintf.cpp \ - ../../corelib/xml/qxmlutils.cpp \ - ../../corelib/xml/qxmlstream.cpp \ - ../../corelib/json/qjson.cpp \ - ../../corelib/json/qjsondocument.cpp \ - ../../corelib/json/qjsonobject.cpp \ - ../../corelib/json/qjsonarray.cpp \ - ../../corelib/json/qjsonvalue.cpp \ - ../../corelib/json/qjsonparser.cpp \ - ../../corelib/json/qjsonwriter.cpp \ ../../xml/dom/qdom.cpp \ ../../xml/sax/qxml.cpp diff --git a/src/tools/tracegen/etw.cpp b/src/tools/tracegen/etw.cpp new file mode 100644 index 0000000000..07f2d114b6 --- /dev/null +++ b/src/tools/tracegen/etw.cpp @@ -0,0 +1,228 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 "etw.h" +#include "provider.h" +#include "helpers.h" +#include "qtheaders.h" + +#include <qfile.h> +#include <qfileinfo.h> +#include <qtextstream.h> +#include <qregexp.h> +#include <quuid.h> + +static inline QString providerVar(const QString &providerName) +{ + return providerName + QLatin1String("_provider"); +} + +static void writeEtwMacro(QTextStream &stream, const Tracepoint::Field &field) +{ + const QString &name = field.name; + + switch (field.backendType) { + case Tracepoint::Field::QtString: + stream << "TraceLoggingCountedWideString(reinterpret_cast<LPCWSTR>(" + << name << ".utf16()), " << name << ".size(), \"" << name << "\")"; + return; + case Tracepoint::Field::QtByteArray: + stream << "TraceLoggingBinary(" << name << ".constData(), " + << name << ".size(), \"" << name << "\")"; + return; + case Tracepoint::Field::QtUrl: + stream << "TraceLoggingValue(" << name << ".toEncoded().constData(), \"" << name << "\")"; + return; + case Tracepoint::Field::QtRect: + stream << "TraceLoggingValue(" << name << ".x(), \"x\"), " + << "TraceLoggingValue(" << name << ".y(), \"y\"), " + << "TraceLoggingValue(" << name << ".width(), \"width\"), " + << "TraceLoggingValue(" << name << ".height(), \"height\")"; + return; + default: + break; + } + + stream << "TraceLoggingValue(" << name << ", \"" << name << "\")"; +} + +static QString createGuid(const QUuid &uuid) +{ + QString guid; + + QTextStream stream(&guid); + + hex(stream); + + stream << "(" + << "0x" << uuid.data1 << ", " + << "0x" << uuid.data2 << ", " + << "0x" << uuid.data3 << ", " + << "0x" << uuid.data4[0] << ", " + << "0x" << uuid.data4[1] << ", " + << "0x" << uuid.data4[2] << ", " + << "0x" << uuid.data4[3] << ", " + << "0x" << uuid.data4[4] << ", " + << "0x" << uuid.data4[5] << ", " + << "0x" << uuid.data4[6] << ", " + << "0x" << uuid.data4[7] + << ")"; + + return guid; +} + +static void writePrologue(QTextStream &stream, const QString &fileName, const QString &providerName) +{ + QUuid uuid = QUuid::createUuidV5(QUuid(), providerName.toLocal8Bit()); + + const QString provider = providerVar(providerName); + const QString guard = includeGuard(fileName); + const QString guid = createGuid(uuid); + const QString guidString = uuid.toString(); + + stream << "#ifndef " << guard << "\n" + << "#define " << guard << "\n" + << "#include <windows.h>\n" + << "#include <TraceLoggingProvider.h>\n"; + + /* TraceLogging API macros cannot deal with UTF8 + * source files, so we work around it like this + */ + stream << "#undef _TlgPragmaUtf8Begin\n" + "#undef _TlgPragmaUtf8End\n" + "#define _TlgPragmaUtf8Begin\n" + "#define _TlgPragmaUtf8End\n"; + + stream << qtHeaders(); + + stream << "\n"; + + stream << "#ifdef TRACEPOINT_DEFINE\n" + << "/* " << guidString << " */\n" + << "TRACELOGGING_DEFINE_PROVIDER(" << provider << ", \"" + << providerName <<"\", " << guid << ");\n\n"; + + stream << "static inline void registerProvider()\n" + << "{\n" + << " TraceLoggingRegister(" << provider << ");\n" + << "}\n\n"; + + stream << "static inline void unregisterProvider()\n" + << "{\n" + << " TraceLoggingUnregister(" << provider << ");\n" + << "}\n"; + + stream << "Q_CONSTRUCTOR_FUNCTION(registerProvider)\n" + << "Q_DESTRUCTOR_FUNCTION(unregisterProvider)\n\n"; + + stream << "#else\n" + << "TRACELOGGING_DECLARE_PROVIDER(" << provider << ");\n" + << "#endif // TRACEPOINT_DEFINE\n\n"; +} + +static void writeEpilogue(QTextStream &stream, const QString &fileName) +{ + stream << "\n#endif // " << includeGuard(fileName) << "\n" + << "#include <private/qtrace_p.h>\n"; +} + +static void writeWrapper(QTextStream &stream, const Tracepoint &tracepoint, + const QString &providerName) +{ + const QString argList = formatFunctionSignature(tracepoint.args); + const QString paramList = formatParameterList(tracepoint.args, ETW); + const QString &name = tracepoint.name; + const QString includeGuard = QStringLiteral("TP_%1_%2").arg(providerName).arg(name).toUpper(); + const QString provider = providerVar(providerName); + + stream << "\n"; + + stream << "inline void trace_" << name << "(" << argList << ")\n" + << "{\n" + << " TraceLoggingWrite(" << provider << ", \"" << name << "\""; + + for (const Tracepoint::Field &field : tracepoint.fields) { + stream << ",\n"; + stream << " "; + writeEtwMacro(stream, field); + } + + stream << ");\n" + << "}\n\n"; + + stream << "inline void do_trace_" << name << "(" << argList << ")\n" + << "{\n" + << " trace_" << name << "(" << paramList << ");\n" + << "}\n"; + + stream << "inline bool trace_" << name << "_enabled()\n" + << "{\n" + << " return TraceLoggingProviderEnabled(" << provider << ", 0, 0);\n" + << "}\n"; +} + +static void writeTracepoints(QTextStream &stream, const Provider &provider) +{ + if (provider.tracepoints.isEmpty()) + return; + + const QString includeGuard = QStringLiteral("TP_%1_PROVIDER").arg(provider.name).toUpper(); + + stream << "#if !defined(" << includeGuard << ") && !defined(TRACEPOINT_DEFINE)\n" + << "#define " << includeGuard << "\n" + << "namespace QtPrivate {\n"; + + for (const Tracepoint &t : provider.tracepoints) + writeWrapper(stream, t, provider.name); + + stream << "} // namespace QtPrivate\n" + << "#endif // " << includeGuard << "\n\n"; +} + +void writeEtw(QFile &file, const Provider &provider) +{ + QTextStream stream(&file); + + const QString fileName = QFileInfo(file.fileName()).fileName(); + + writePrologue(stream, fileName, provider.name); + writeTracepoints(stream, provider); + writeEpilogue(stream, fileName); +} + diff --git a/src/tools/tracegen/etw.h b/src/tools/tracegen/etw.h new file mode 100644 index 0000000000..5fc9b57eaa --- /dev/null +++ b/src/tools/tracegen/etw.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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$ +** +****************************************************************************/ + +#ifndef ETW_H +#define ETW_H + +struct Provider; +class QFile; + +void writeEtw(QFile &device, const Provider &p); + +#endif // ETW_H diff --git a/src/tools/tracegen/helpers.cpp b/src/tools/tracegen/helpers.cpp new file mode 100644 index 0000000000..f0ac7ed47f --- /dev/null +++ b/src/tools/tracegen/helpers.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 "helpers.h" +#include <qdebug.h> + +QString includeGuard(const QString &filename) +{ + QString guard = filename.toUpper(); + + for (int i = 0; i < guard.size(); ++i) { + if (!guard.at(i).isLetterOrNumber()) + guard[i] = QChar('_'); + } + + return guard; +} + +template <typename T> +static QString joinArguments(const QVector<Tracepoint::Argument> &args, T joinFunction) +{ + QString ret; + bool first = true; + + for (const Tracepoint::Argument &arg : args) { + if (!first) + ret += QLatin1String(", "); + + ret += joinFunction(arg); + + first = false; + } + + return ret; +} + +QString formatFunctionSignature(const QVector<Tracepoint::Argument> &args) +{ + return joinArguments(args, [](const Tracepoint::Argument &arg) { + return QStringLiteral("%1 %2").arg(arg.type).arg(arg.name); + }); +} + +QString formatParameterList(const QVector<Tracepoint::Argument> &args, ParamType type) +{ + if (type == LTTNG) { + QString ret; + + for (const Tracepoint::Argument &arg : args) + ret += QLatin1String(", ") + arg.name; + + return ret; + } + + return joinArguments(args, [](const Tracepoint::Argument &arg) { return arg.name; }); +} diff --git a/src/tools/tracegen/helpers.h b/src/tools/tracegen/helpers.h new file mode 100644 index 0000000000..77f16a0da6 --- /dev/null +++ b/src/tools/tracegen/helpers.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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$ +** +****************************************************************************/ + +#ifndef HELPERS_H +#define HELPERS_H + +#include "provider.h" + +#include <qvector.h> +#include <qstring.h> + +enum ParamType { + LTTNG, + ETW +}; + +QString includeGuard(const QString &filename); +QString formatFunctionSignature(const QVector<Tracepoint::Argument> &args); +QString formatParameterList(const QVector<Tracepoint::Argument> &args, ParamType type); + +#endif // HELPERS_H diff --git a/src/tools/tracegen/lttng.cpp b/src/tools/tracegen/lttng.cpp new file mode 100644 index 0000000000..6c0d8cc88b --- /dev/null +++ b/src/tools/tracegen/lttng.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 "lttng.h" +#include "provider.h" +#include "helpers.h" +#include "panic.h" +#include "qtheaders.h" + +#include <qfile.h> +#include <qfileinfo.h> +#include <qtextstream.h> +#include <qregexp.h> +#include <qdebug.h> + +static void writeCtfMacro(QTextStream &stream, const Tracepoint::Field &field) +{ + const QString ¶mType = field.paramType; + const QString &name = field.name; + const QString &seqLen = field.seqLen; + const int arrayLen = field.arrayLen; + + switch (field.backendType) { + case Tracepoint::Field::Array: + stream << "ctf_array(" <<paramType << ", " + << name << ", " << name << ", " << arrayLen << ")"; + return; + case Tracepoint::Field::Sequence: + stream << "ctf_sequence(" << paramType + << ", " << name << ", " << name + << ", unsigned int, " << seqLen << ")"; + return; + case Tracepoint::Field::Integer: + stream << "ctf_integer(" << paramType << ", " << name << ", " << name << ")"; + return; + case Tracepoint::Field::Float: + stream << "ctf_float(" << paramType << ", " << name << ", " << name << ")"; + return; + case Tracepoint::Field::String: + stream << "ctf_string(" << name << ", " << name << ")"; + return; + case Tracepoint::Field::QtString: + stream << "ctf_sequence(const ushort, " << name << ", " + << name << ".utf16(), unsigned int, " << name << ".size())"; + return; + case Tracepoint::Field::QtByteArray: + stream << "ctf_sequence(const char, " << name << ", " + << name << ".constData(), unsigned int, " << name << ".size())"; + return; + case Tracepoint::Field::QtUrl: + stream << "ctf_sequence(const char, " << name << ", " + << name << ".toEncoded().constData(), unsigned int, " + << name << ".toEncoded().size())"; + return; + case Tracepoint::Field::QtRect: + stream << "ctf_integer(int, x, " << name << ".x()) " + << "ctf_integer(int, y, " << name << ".y()) " + << "ctf_integer(int, width, " << name << ".width()) " + << "ctf_integer(int, height, " << name << ".height()) "; + return; + case Tracepoint::Field::Unknown: + panic("Cannot deduce CTF type for '%s %s", qPrintable(paramType), qPrintable(name)); + break; + } +} + +static void writePrologue(QTextStream &stream, const QString &fileName, const QString &providerName) +{ + stream << "#undef TRACEPOINT_PROVIDER\n"; + stream << "#define TRACEPOINT_PROVIDER " << providerName << "\n\n"; + + stream << qtHeaders(); + + const QString guard = includeGuard(fileName); + + stream << "\n"; + + /* the first guard is the usual one, the second is required + * by LTTNG to force the re-evaluation of TRACEPOINT_* macros + */ + stream << "#if !defined(" << guard << ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n"; + + stream << "#define " << guard << "\n\n" + << "#undef TRACEPOINT_INCLUDE\n" + << "#define TRACEPOINT_INCLUDE \"" << fileName << "\"\n\n"; + + stream << "#include <lttng/tracepoint.h>\n\n"; +} + +static void writeEpilogue(QTextStream &stream, const QString &fileName) +{ + stream << "\n"; + stream << "#endif // " << includeGuard(fileName) << "\n" + << "#include <lttng/tracepoint-event.h>\n" + << "#include <private/qtrace_p.h>\n"; +} + +static void writeWrapper(QTextStream &stream, + const Tracepoint &tracepoint, const QString &providerName) +{ + const QString argList = formatFunctionSignature(tracepoint.args); + const QString paramList = formatParameterList(tracepoint.args, LTTNG); + const QString &name = tracepoint.name; + const QString includeGuard = QStringLiteral("TP_%1_%2").arg(providerName).arg(name).toUpper(); + + /* prevents the redefinion of the inline wrapper functions + * once LTTNG recursively includes this header file + */ + stream << "\n" + << "#ifndef " << includeGuard << "\n" + << "#define " << includeGuard << "\n" + << "namespace QtPrivate {\n"; + + stream << "inline void trace_" << name << "(" << argList << ")\n" + << "{\n" + << " tracepoint(" << providerName << ", " << name << paramList << ");\n" + << "}\n"; + + stream << "inline void do_trace_" << name << "(" << argList << ")\n" + << "{\n" + << " do_tracepoint(" << providerName << ", " << name << paramList << ");\n" + << "}\n"; + + stream << "inline bool trace_" << name << "_enabled()\n" + << "{\n" + << " return tracepoint_enabled(" << providerName << ", " << name << ");\n" + << "}\n"; + + stream << "} // namespace QtPrivate\n" + << "#endif // " << includeGuard << "\n\n"; +} + +static void writeTracepoint(QTextStream &stream, + const Tracepoint &tracepoint, const QString &providerName) +{ + stream << "TRACEPOINT_EVENT(\n" + << " " << providerName << ",\n" + << " " << tracepoint.name << ",\n" + << " TP_ARGS("; + + const char *comma = nullptr; + + for (const Tracepoint::Argument &arg : tracepoint.args) { + stream << comma << arg.type << ", " << arg.name; + comma = ", "; + } + + stream << "),\n" + << " TP_FIELDS("; + + const char *newline = nullptr; + + for (const Tracepoint::Field &f : tracepoint.fields) { + stream << newline; + writeCtfMacro(stream, f); + newline = "\n "; + } + + stream << ")\n)\n\n"; +} + +static void writeTracepoints(QTextStream &stream, const Provider &provider) +{ + for (const Tracepoint &t : provider.tracepoints) { + writeTracepoint(stream, t, provider.name); + writeWrapper(stream, t, provider.name); + } +} + +void writeLttng(QFile &file, const Provider &provider) +{ + QTextStream stream(&file); + + const QString fileName = QFileInfo(file.fileName()).fileName(); + + writePrologue(stream, fileName, provider.name); + writeTracepoints(stream, provider); + writeEpilogue(stream, fileName); +} diff --git a/src/tools/tracegen/lttng.h b/src/tools/tracegen/lttng.h new file mode 100644 index 0000000000..0307b375bc --- /dev/null +++ b/src/tools/tracegen/lttng.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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$ +** +****************************************************************************/ + +#ifndef LTTNG_H +#define LTTNG_H + +struct Provider; +class QFile; + +void writeLttng(QFile &device, const Provider &p); + +#endif // LTTNG_H diff --git a/src/tools/tracegen/panic.cpp b/src/tools/tracegen/panic.cpp new file mode 100644 index 0000000000..d1e207764e --- /dev/null +++ b/src/tools/tracegen/panic.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 "panic.h" + +#include <cstdarg> +#include <cstdio> +#include <cstdlib> + +void panic(const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "tracegen: fatal: "); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fputc('\n', stderr); + + exit(EXIT_FAILURE); +} diff --git a/src/tools/tracegen/panic.h b/src/tools/tracegen/panic.h new file mode 100644 index 0000000000..c6b195af00 --- /dev/null +++ b/src/tools/tracegen/panic.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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$ +** +****************************************************************************/ + +#ifndef PANIC_H +#define PANIC_H + +void panic(const char *fmt, ...); + +#endif // PANIC_H diff --git a/src/tools/tracegen/provider.cpp b/src/tools/tracegen/provider.cpp new file mode 100644 index 0000000000..00e105377e --- /dev/null +++ b/src/tools/tracegen/provider.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 "provider.h" +#include "panic.h" + +#include <qfile.h> +#include <qfileinfo.h> +#include <qtextstream.h> +#include <qregexp.h> +#include <qstring.h> + +#ifdef TRACEGEN_DEBUG +#include <qdebug.h> + +static void dumpTracepoint(const Tracepoint &t) +{ + qDebug() << "=== BEGIN TRACEPOINT ==="; + qDebug() << "name:" << t.name; + qDebug() << "ARGS\n"; + + int j = 0; + + for (auto i = t.args.constBegin(); i != t.args.constEnd(); ++i) { + qDebug() << "ARG[" << j << "] type:" << i->type; + qDebug() << "ARG[" << j << "] name:" << i->name; + qDebug() << "ARG[" << j << "] arrayLen:" << i->arrayLen; + ++j; + } + + qDebug() << "\nFIELDS\n"; + + j = 0; + + for (auto i = t.fields.constBegin(); i != t.fields.constEnd(); ++i) { + qDebug() << "FIELD[" << j << "] backend_type" << static_cast<int>(i->backendType); + qDebug() << "FIELD[" << j << "] param_type" << i->paramType; + qDebug() << "FIELD[" << j << "] name" << i->name; + qDebug() << "FIELD[" << j << "] arrayLen" << i->arrayLen; + qDebug() << "FIELD[" << j << "] seqLen" << i->seqLen; + ++j; + } + + qDebug() << "=== END TRACEPOINT ===\n"; + +} +#endif + +static inline int arrayLength(const QString &rawType) +{ + /* matches the length of an ordinary array type + * Ex: foo[10] yields '10' + */ + static const QRegExp rx(QStringLiteral(".*\\[([0-9]+)\\].*")); + + if (!rx.exactMatch(rawType.trimmed())) + return 0; + + return rx.cap(1).toInt(); +} + +static inline QString sequenceLength(const QString &rawType) +{ + /* matches the identifier pointing to length of a CTF sequence type, which is + * a dynamic sized array. + * Ex: in qcoreapplication_foo(const char[len], some_string, unsigned int, * len) + * it will match the 'len' part of 'const char[len]') + */ + static const QRegExp rx(QStringLiteral(".*\\[([A-Za-z_][A-Za-z_0-9]*)\\].*")); + + if (!rx.exactMatch(rawType.trimmed())) + return QString(); + + return rx.cap(1); +} + +static QString decayArrayToPointer(QString type) +{ + /* decays an array to a pointer, i.e., if 'type' holds int[10], + * this function returns 'int *' + */ + static QRegExp rx(QStringLiteral("\\[(.+)\\]")); + + rx.setMinimal(true); + return type.replace(rx, QStringLiteral("*")); +} + +static QString removeBraces(QString type) +{ + static const QRegExp rx(QStringLiteral("\\[.*\\]")); + + return type.remove(rx); +} + +static Tracepoint::Field::BackendType backendType(QString rawType) +{ + static const struct { + const char *type; + Tracepoint::Field::BackendType backendType; + } typeTable[] = { + { "bool", Tracepoint::Field::Integer }, + { "short_int", Tracepoint::Field::Integer }, + { "signed_short", Tracepoint::Field::Integer }, + { "signed_short_int", Tracepoint::Field::Integer }, + { "unsigned_short", Tracepoint::Field::Integer }, + { "unsigned_short_int", Tracepoint::Field::Integer }, + { "int", Tracepoint::Field::Integer }, + { "signed", Tracepoint::Field::Integer }, + { "signed_int", Tracepoint::Field::Integer }, + { "unsigned", Tracepoint::Field::Integer }, + { "unsigned_int", Tracepoint::Field::Integer }, + { "long", Tracepoint::Field::Integer }, + { "long_int", Tracepoint::Field::Integer }, + { "signed_long", Tracepoint::Field::Integer }, + { "signed_long_int", Tracepoint::Field::Integer }, + { "unsigned_long", Tracepoint::Field::Integer }, + { "unsigned_long_int", Tracepoint::Field::Integer }, + { "long_long", Tracepoint::Field::Integer }, + { "long_long_int", Tracepoint::Field::Integer }, + { "signed_long_long", Tracepoint::Field::Integer }, + { "signed_long_long_int", Tracepoint::Field::Integer }, + { "unsigned_long_long", Tracepoint::Field::Integer }, + { "char", Tracepoint::Field::Integer }, + { "float", Tracepoint::Field::Float }, + { "double", Tracepoint::Field::Float }, + { "long_double", Tracepoint::Field::Float }, + { "char_ptr", Tracepoint::Field::String }, + { "QString", Tracepoint::Field::QtString }, + { "QByteArray", Tracepoint::Field::QtByteArray }, + { "QUrl", Tracepoint::Field::QtUrl }, + { "QRect", Tracepoint::Field::QtRect } + }; + + auto backendType = [](const QString &rawType) { + + static const size_t tableSize = sizeof (typeTable) / sizeof (typeTable[0]); + + for (size_t i = 0; i < tableSize; ++i) { + if (rawType == QLatin1String(typeTable[i].type)) + return typeTable[i].backendType; + } + + return Tracepoint::Field::Unknown; + }; + + if (arrayLength(rawType) > 0) + return Tracepoint::Field::Array; + + if (!sequenceLength(rawType).isNull()) + return Tracepoint::Field::Sequence; + + static const QRegExp constMatch(QStringLiteral("\\bconst\\b")); + rawType.remove(constMatch); + rawType.remove(QLatin1Char('&')); + + static const QRegExp ptrMatch(QStringLiteral("\\s*\\*\\s*")); + rawType.replace(ptrMatch, QStringLiteral("_ptr")); + rawType = rawType.trimmed(); + rawType.replace(QStringLiteral(" "), QStringLiteral("_")); + + return backendType(rawType.trimmed()); +} + +static Tracepoint parseTracepoint(const QString &name, const QStringList &args, + const QString &fileName, const int lineNumber) +{ + Tracepoint t; + t.name = name; + + if (args.isEmpty()) + return t; + + auto i = args.constBegin(); + auto end = args.constEnd(); + int argc = 0; + + static const QRegExp rx(QStringLiteral("(.*)\\b([A-Za-z_][A-Za-z0-9_]*)$")); + + while (i != end) { + rx.exactMatch(*i); + + const QString type = rx.cap(1).trimmed(); + + if (type.isNull()) { + panic("Missing parameter type for argument %d of %s (%s:%d)", + argc, qPrintable(name), qPrintable(fileName), lineNumber); + } + + const QString name = rx.cap(2).trimmed(); + + if (name.isNull()) { + panic("Missing parameter name for argument %d of %s (%s:%d)", + argc, qPrintable(name), qPrintable(fileName), lineNumber); + } + + int arrayLen = arrayLength(type); + + Tracepoint::Argument a; + a.arrayLen = arrayLen; + a.name = name; + a.type = decayArrayToPointer(type); + + t.args << std::move(a); + + Tracepoint::Field f; + f.backendType = backendType(type); + f.paramType = removeBraces(type); + f.name = name; + f.arrayLen = arrayLen; + f.seqLen = sequenceLength(type); + + t.fields << std::move(f); + + ++i; + } + + return t; +} + +Provider parseProvider(const QString &filename) +{ + QFile f(filename); + + if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) + panic("Cannot open %s: %s", qPrintable(filename), qPrintable(f.errorString())); + + QTextStream s(&f); + + static const QRegExp tracedef(QStringLiteral("([A-Za-z][A-Za-z0-9_]*)\\((.*)\\)")); + + int lineNumber = 0; + + Provider provider; + provider.name = QFileInfo(filename).baseName(); + + for (;;) { + QString line = s.readLine().trimmed(); + + if (line.isNull()) + break; + + if (line.isEmpty() || line.startsWith(QStringLiteral("#"))) { + ++lineNumber; + continue; + } + + if (tracedef.exactMatch(line)) { + const QString name = tracedef.cap(1); + QStringList args = tracedef.cap(2).split(QStringLiteral(","), QString::SkipEmptyParts); + + if (args.at(0).isNull()) + args.clear(); + + provider.tracepoints << parseTracepoint(name, args, filename, lineNumber); + } else { + panic("Syntax error whilre processing %s on line %d", qPrintable(filename), lineNumber); + } + + ++lineNumber; + } + +#ifdef TRACEGEN_DEBUG + for (auto i = provider.tracepoints.constBegin(); i != provider.tracepoints.constEnd(); ++i) + dumpTracepoint(*i); +#endif + + return provider; +} diff --git a/src/tools/tracegen/provider.h b/src/tools/tracegen/provider.h new file mode 100644 index 0000000000..d8cbd2662d --- /dev/null +++ b/src/tools/tracegen/provider.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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$ +** +****************************************************************************/ + +#ifndef PROVIDER_H +#define PROVIDER_H + +#include <qvector.h> +#include <qstring.h> +#include <qtypeinfo.h> + +struct Tracepoint +{ + struct Argument + { + QString type; + QString name; + int arrayLen; + }; + + struct Field + { + enum BackendType { + Array, + Sequence, + Integer, + Float, + String, + QtString, + QtByteArray, + QtUrl, + QtRect, + Unknown + }; + + BackendType backendType; + QString paramType; + QString name; + int arrayLen; + QString seqLen; + }; + + QString name; + QVector<Argument> args; + QVector<Field> fields; +}; + +struct Provider +{ + QString name; + QVector<Tracepoint> tracepoints; +}; + +Provider parseProvider(const QString &filename); + +Q_DECLARE_TYPEINFO(Tracepoint::Argument, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracepoint::Field, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Tracepoint, Q_MOVABLE_TYPE); + +#endif // PROVIDER_H diff --git a/src/tools/tracegen/qtheaders.cpp b/src/tools/tracegen/qtheaders.cpp new file mode 100644 index 0000000000..eec3488a6d --- /dev/null +++ b/src/tools/tracegen/qtheaders.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 "qtheaders.h" + +const char *qtHeaders() +{ + static const char headers[] = "" + "#include <QString>\n" + "#include <QByteArray>\n" + "#include <QUrl>\n" + "#include <QRect>\n"; + + return headers; +} diff --git a/src/tools/tracegen/qtheaders.h b/src/tools/tracegen/qtheaders.h new file mode 100644 index 0000000000..b80d374ca8 --- /dev/null +++ b/src/tools/tracegen/qtheaders.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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$ +** +****************************************************************************/ + +#ifndef QTHEADERS_H +#define QTHEADERS_H + +const char *qtHeaders(); + +#endif // QTHEADERS_H diff --git a/src/tools/tracegen/tracegen.cpp b/src/tools/tracegen/tracegen.cpp new file mode 100644 index 0000000000..978fe406d0 --- /dev/null +++ b/src/tools/tracegen/tracegen.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com> +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 "provider.h" +#include "lttng.h" +#include "etw.h" +#include "panic.h" + +#include <qstring.h> +#include <qfile.h> + +enum class Target +{ + LTTNG, + ETW +}; + +static inline void usage(int status) +{ + printf("Usage: tracegen <lttng|etw> <input file> <output file>\n"); + exit(status); +} + +static void parseArgs(int argc, char *argv[], Target *target, QString *inFile, QString *outFile) +{ + if (argc == 1) + usage(EXIT_SUCCESS); + if (argc != 4) + usage(EXIT_FAILURE); + + const char *targetString = argv[1]; + + if (qstrcmp(targetString, "lttng") == 0) { + *target = Target::LTTNG; + } else if (qstrcmp(targetString, "etw") == 0) { + *target = Target::ETW; + } else { + fprintf(stderr, "Invalid target: %s\n", targetString); + usage(EXIT_FAILURE); + } + + *inFile = QLatin1String(argv[2]); + *outFile = QLatin1String(argv[3]); +} + +int main(int argc, char *argv[]) +{ + Target target = Target::LTTNG; + QString inFile; + QString outFile; + + parseArgs(argc, argv, &target, &inFile, &outFile); + + Provider p = parseProvider(inFile); + + QFile out(outFile); + + if (!out.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + panic("Cannot open '%s' for writing: %s", + qPrintable(outFile), qPrintable(out.errorString())); + } + + switch (target) { + case Target::LTTNG: + writeLttng(out, p); + break; + case Target::ETW: + writeEtw(out, p); + break; + } + + return 0; +} diff --git a/src/tools/tracegen/tracegen.pro b/src/tools/tracegen/tracegen.pro new file mode 100644 index 0000000000..20f0bb2914 --- /dev/null +++ b/src/tools/tracegen/tracegen.pro @@ -0,0 +1,21 @@ +option(host_build) +CONFIG += force_bootstrap + +SOURCES += \ + etw.cpp \ + helpers.cpp \ + lttng.cpp \ + panic.cpp \ + provider.cpp \ + qtheaders.cpp \ + tracegen.cpp + +HEADERS += \ + etw.h \ + helpers.h \ + lttng.h \ + panic.h \ + provider.h \ + qtheaders.h + +load(qt_tool) diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp index f0423ca825..efcf4cdc8b 100644 --- a/src/widgets/accessible/simplewidgets.cpp +++ b/src/widgets/accessible/simplewidgets.cpp @@ -704,6 +704,8 @@ QString QAccessibleLineEdit::text(QAccessible::Text t) const } if (str.isEmpty()) str = QAccessibleWidget::text(t); + if (str.isEmpty() && t == QAccessible::Description) + str = lineEdit()->placeholderText(); return str; } diff --git a/src/widgets/dialogs/qfileinfogatherer_p.h b/src/widgets/dialogs/qfileinfogatherer_p.h index bb13d4eb01..cc82f42850 100644 --- a/src/widgets/dialogs/qfileinfogatherer_p.h +++ b/src/widgets/dialogs/qfileinfogatherer_p.h @@ -167,6 +167,13 @@ public: explicit QFileInfoGatherer(QObject *parent = 0); ~QFileInfoGatherer(); +#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN) + QStringList watchedFiles() const { return watcher->files(); } + QStringList watchedDirectories() const { return watcher->directories(); } + void watchPaths(const QStringList &paths) { watcher->addPaths(paths); } + void unwatchPaths(const QStringList &paths) { watcher->removePaths(paths); } +#endif // filesystemwatcher && Q_OS_WIN + // only callable from this->thread(): void clear(); void removePath(const QString &path); diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index 14ac6ad31b..33b8b51216 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -207,14 +207,17 @@ bool QFileSystemModel::remove(const QModelIndex &aindex) const QString path = d->filePath(aindex); const QFileInfo fileInfo(path); +#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN) + // QTBUG-65683: Remove file system watchers prior to deletion to prevent + // failure due to locked files on Windows. + const QStringList watchedPaths = d->unwatchPathsAt(aindex); +#endif // filesystemwatcher && Q_OS_WIN const bool success = (fileInfo.isFile() || fileInfo.isSymLink()) ? QFile::remove(path) : QDir(path).removeRecursively(); -#ifndef QT_NO_FILESYSTEMWATCHER - if (success) { - QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func()); - d->fileInfoGatherer.removePath(path); - } -#endif +#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN) + if (!success) + d->watchPaths(watchedPaths); +#endif // filesystemwatcher && Q_OS_WIN return success; } @@ -851,6 +854,20 @@ QIcon QFileSystemModelPrivate::icon(const QModelIndex &index) const return node(index)->icon(); } +static void displayRenameFailedMessage(const QString &newName) +{ +#if QT_CONFIG(messagebox) + const QString message = + QFileSystemModel::tr("<b>The name \"%1\" cannot be used.</b>" + "<p>Try using another name, with fewer characters or no punctuation marks.") + .arg(newName); + QMessageBox::information(nullptr, QFileSystemModel::tr("Invalid filename"), + message, QMessageBox::Ok); +#else + Q_UNUSED(newName) +#endif // QT_CONFIG(messagebox) +} + /*! \reimp */ @@ -871,15 +888,21 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in const QString parentPath = filePath(parent(idx)); - if (newName.isEmpty() - || QDir::toNativeSeparators(newName).contains(QDir::separator()) - || !QDir(parentPath).rename(oldName, newName)) { -#if QT_CONFIG(messagebox) - QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"), - QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.") - .arg(newName), - QMessageBox::Ok); -#endif // QT_CONFIG(messagebox) + if (newName.isEmpty() || QDir::toNativeSeparators(newName).contains(QDir::separator())) { + displayRenameFailedMessage(newName); + return false; + } + +#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN) + // QTBUG-65683: Remove file system watchers prior to renaming to prevent + // failure due to locked files on Windows. + const QStringList watchedPaths = d->unwatchPathsAt(idx); +#endif // filesystemwatcher && Q_OS_WIN + if (!QDir(parentPath).rename(oldName, newName)) { +#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN) + d->watchPaths(watchedPaths); +#endif + displayRenameFailedMessage(newName); return false; } else { /* @@ -1882,6 +1905,46 @@ void QFileSystemModelPrivate::_q_resolvedName(const QString &fileName, const QSt resolvedSymLinks[fileName] = resolvedName; } +#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN) +// Remove file system watchers at/below the index and return a list of previously +// watched files. This should be called prior to operations like rename/remove +// which might fail due to watchers on platforms like Windows. The watchers +// should be restored on failure. +QStringList QFileSystemModelPrivate::unwatchPathsAt(const QModelIndex &index) +{ + const QFileSystemModelPrivate::QFileSystemNode *indexNode = node(index); + if (indexNode == nullptr) + return QStringList(); + const Qt::CaseSensitivity caseSensitivity = indexNode->caseSensitive() + ? Qt::CaseSensitive : Qt::CaseInsensitive; + const QString path = indexNode->fileInfo().absoluteFilePath(); + + QStringList result; + const auto filter = [path, caseSensitivity] (const QString &watchedPath) + { + const int pathSize = path.size(); + if (pathSize == watchedPath.size()) { + return path.compare(watchedPath, caseSensitivity) == 0; + } else if (watchedPath.size() > pathSize) { + return watchedPath.at(pathSize) == QLatin1Char('/') + && watchedPath.startsWith(path, caseSensitivity); + } + return false; + }; + + const QStringList &watchedFiles = fileInfoGatherer.watchedFiles(); + std::copy_if(watchedFiles.cbegin(), watchedFiles.cend(), + std::back_inserter(result), filter); + + const QStringList &watchedDirectories = fileInfoGatherer.watchedDirectories(); + std::copy_if(watchedDirectories.cbegin(), watchedDirectories.cend(), + std::back_inserter(result), filter); + + fileInfoGatherer.unwatchPaths(result); + return result; +} +#endif // filesystemwatcher && Q_OS_WIN + /*! \internal */ diff --git a/src/widgets/dialogs/qfilesystemmodel_p.h b/src/widgets/dialogs/qfilesystemmodel_p.h index e8bae4f659..a2a02e2d41 100644 --- a/src/widgets/dialogs/qfilesystemmodel_p.h +++ b/src/widgets/dialogs/qfilesystemmodel_p.h @@ -297,9 +297,13 @@ public: static int naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs); QDir rootDir; -#ifndef QT_NO_FILESYSTEMWATCHER +#if QT_CONFIG(filesystemwatcher) +# ifdef Q_OS_WIN + QStringList unwatchPathsAt(const QModelIndex &); + void watchPaths(const QStringList &paths) { fileInfoGatherer.watchPaths(paths); } +# endif // Q_OS_WIN QFileInfoGatherer fileInfoGatherer; -#endif +#endif // filesystemwatcher QTimer delayedSortTimer; bool forceSort; int sortColumn; diff --git a/src/widgets/doc/snippets/common-table-model/model.cpp b/src/widgets/doc/snippets/common-table-model/model.cpp index 96df100f26..2f6e9f1144 100644 --- a/src/widgets/doc/snippets/common-table-model/model.cpp +++ b/src/widgets/doc/snippets/common-table-model/model.cpp @@ -68,7 +68,7 @@ TableModel::TableModel(int rows, int columns, QObject *parent) QStringList newList; for (int column = 0; column < qMax(1, columns); ++column) { - newList.append(""); + newList.append(QString()); } for (int row = 0; row < qMax(1, rows); ++row) { @@ -129,9 +129,9 @@ QVariant TableModel::headerData(int section, Qt::Orientation orientation, return QVariant(); if (orientation == Qt::Horizontal) - return QString("Column %1").arg(section); + return QStringLiteral("Column %1").arg(section); else - return QString("Row %1").arg(section); + return QStringLiteral("Row %1").arg(section); } /*! @@ -164,7 +164,7 @@ bool TableModel::setData(const QModelIndex &index, return false; rowList[index.row()][index.column()] = value.toString(); - emit dataChanged(index, index); + emit dataChanged(index, index, {role}); return true; } @@ -180,7 +180,7 @@ bool TableModel::insertRows(int position, int rows, const QModelIndex &parent) for (int row = 0; row < rows; ++row) { QStringList items; for (int column = 0; column < columns; ++column) - items.append(""); + items.append(QString()); rowList.insert(position, items); } @@ -202,7 +202,7 @@ bool TableModel::insertColumns(int position, int columns, for (int row = 0; row < rows; ++row) { for (int column = position; column < columns; ++column) { - rowList[row].insert(position, ""); + rowList[row].insert(position, QString()); } } diff --git a/src/widgets/doc/snippets/common-table-model/model.h b/src/widgets/doc/snippets/common-table-model/model.h index 68e6c00702..5f152e0e78 100644 --- a/src/widgets/doc/snippets/common-table-model/model.h +++ b/src/widgets/doc/snippets/common-table-model/model.h @@ -60,22 +60,22 @@ class TableModel : public QAbstractTableModel Q_OBJECT public: - TableModel(int rows = 1, int columns = 1, QObject *parent = 0); + TableModel(int rows = 1, int columns = 1, QObject *parent = nullptr); - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; + int role = Qt::DisplayRole) const override; - Qt::ItemFlags flags(const QModelIndex &index) const; + Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, - int role = Qt::EditRole); + int role = Qt::EditRole) override; - bool insertRows(int position, int rows, const QModelIndex &parent = QModelIndex()); - bool insertColumns(int position, int columns, const QModelIndex &parent = QModelIndex()); - bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()); - bool removeColumns(int position, int columns, const QModelIndex &parent = QModelIndex()); + bool insertRows(int position, int rows, const QModelIndex &parent = QModelIndex()) override; + bool insertColumns(int position, int columns, const QModelIndex &parent = QModelIndex()) override; + bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()) override; + bool removeColumns(int position, int columns, const QModelIndex &parent = QModelIndex()) override; private: QList<QStringList> rowList; diff --git a/src/widgets/doc/snippets/stringlistmodel/model.cpp b/src/widgets/doc/snippets/stringlistmodel/model.cpp index f07f6b254f..52e78847d2 100644 --- a/src/widgets/doc/snippets/stringlistmodel/model.cpp +++ b/src/widgets/doc/snippets/stringlistmodel/model.cpp @@ -135,9 +135,9 @@ QVariant StringListModel::headerData(int section, Qt::Orientation orientation, return QVariant(); if (orientation == Qt::Horizontal) - return QString("Column %1").arg(section); + return QStringLiteral("Column %1").arg(section); else - return QString("Row %1").arg(section); + return QStringLiteral("Row %1").arg(section); } //! [2] @@ -174,7 +174,7 @@ bool StringListModel::setData(const QModelIndex &index, if (index.isValid() && role == Qt::EditRole) { stringList.replace(index.row(), value.toString()); - emit dataChanged(index, index); + emit dataChanged(index, index, {role}); return true; } //! [4] //! [5] diff --git a/src/widgets/doc/snippets/stringlistmodel/model.h b/src/widgets/doc/snippets/stringlistmodel/model.h index 50769ef67f..7012152b27 100644 --- a/src/widgets/doc/snippets/stringlistmodel/model.h +++ b/src/widgets/doc/snippets/stringlistmodel/model.h @@ -61,26 +61,26 @@ class StringListModel : public QAbstractListModel Q_OBJECT public: - StringListModel(const QStringList &strings, QObject *parent = 0) + StringListModel(const QStringList &strings, QObject *parent = nullptr) : QAbstractListModel(parent), stringList(strings) {} - int rowCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, //! [0] //! [1] - int role = Qt::DisplayRole) const; + int role = Qt::DisplayRole) const override; //! [1] //! [2] - Qt::ItemFlags flags(const QModelIndex &index) const; + Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, //! [2] //! [3] - int role = Qt::EditRole); + int role = Qt::EditRole) override; //! [3] //! [4] - bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()); - bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()); + bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; + bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; //! [4] //! [5] diff --git a/src/widgets/graphicsview/qgraphicsscene.h b/src/widgets/graphicsview/qgraphicsscene.h index 5ecd2baab8..8efbcd273e 100644 --- a/src/widgets/graphicsview/qgraphicsscene.h +++ b/src/widgets/graphicsview/qgraphicsscene.h @@ -288,11 +288,7 @@ protected: QWidget *widget = nullptr); protected Q_SLOTS: - // ### Qt 6: make unconditional -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - virtual -#endif - bool focusNextPrevChild(bool next); + QT6_VIRTUAL bool focusNextPrevChild(bool next); Q_SIGNALS: void changed(const QList<QRectF> ®ion); diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 50287df6e0..585cfddff5 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -2848,14 +2848,18 @@ void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logical if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex && isHeaderArrowOnTheSide) margin += style()->pixelMetric(QStyle::PM_HeaderMarkSize, 0, this); - if (d->textElideMode != Qt::ElideNone) - opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - margin); - - QVariant variant = d->model->headerData(logicalIndex, d->orientation, - Qt::DecorationRole); + const QVariant variant = d->model->headerData(logicalIndex, d->orientation, + Qt::DecorationRole); opt.icon = qvariant_cast<QIcon>(variant); if (opt.icon.isNull()) opt.icon = qvariant_cast<QPixmap>(variant); + if (!opt.icon.isNull()) // see CT_HeaderSection + margin += style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this) + + style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this); + + if (d->textElideMode != Qt::ElideNone) + opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - margin); + QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation, Qt::ForegroundRole); if (foregroundBrush.canConvert<QBrush>()) diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp index ad8aac1415..1fedad80aa 100644 --- a/src/widgets/itemviews/qlistwidget.cpp +++ b/src/widgets/itemviews/qlistwidget.cpp @@ -412,10 +412,10 @@ QList<QListWidgetItem*>::iterator QListModel::sortedInsertionIterator( return std::lower_bound(begin, end, item, QListModelGreaterThan()); } -void QListModel::itemChanged(QListWidgetItem *item) +void QListModel::itemChanged(QListWidgetItem *item, const QVector<int> &roles) { - QModelIndex idx = index(item); - emit dataChanged(idx, idx); + const QModelIndex idx = index(item); + emit dataChanged(idx, idx, roles); } QStringList QListModel::mimeTypes() const @@ -711,8 +711,12 @@ void QListWidgetItem::setData(int role, const QVariant &value) } if (!found) d->values.append(QWidgetItemData(role, value)); - if (QListModel *model = (view ? qobject_cast<QListModel*>(view->model()) : 0)) - model->itemChanged(this); + if (QListModel *model = (view ? qobject_cast<QListModel*>(view->model()) : nullptr)) { + const QVector<int> roles((role == Qt::DisplayRole) ? + QVector<int>({Qt::DisplayRole, Qt::EditRole}) : + QVector<int>({role})); + model->itemChanged(this, roles); + } } /*! @@ -954,7 +958,8 @@ QDataStream &operator>>(QDataStream &in, QListWidgetItem &item) \sa Qt::ItemFlags */ -void QListWidgetItem::setFlags(Qt::ItemFlags aflags) { +void QListWidgetItem::setFlags(Qt::ItemFlags aflags) +{ itemFlags = aflags; if (QListModel *model = (view ? qobject_cast<QListModel*>(view->model()) : 0)) model->itemChanged(this); diff --git a/src/widgets/itemviews/qlistwidget.h b/src/widgets/itemviews/qlistwidget.h index 3caa5ce6f2..8a31411429 100644 --- a/src/widgets/itemviews/qlistwidget.h +++ b/src/widgets/itemviews/qlistwidget.h @@ -269,6 +269,7 @@ Q_SIGNALS: void itemDoubleClicked(QListWidgetItem *item); void itemActivated(QListWidgetItem *item); void itemEntered(QListWidgetItem *item); + // ### Qt 6: add changed roles void itemChanged(QListWidgetItem *item); void currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); diff --git a/src/widgets/itemviews/qlistwidget_p.h b/src/widgets/itemviews/qlistwidget_p.h index 492b05ff07..30b5016db6 100644 --- a/src/widgets/itemviews/qlistwidget_p.h +++ b/src/widgets/itemviews/qlistwidget_p.h @@ -119,7 +119,7 @@ public: const QList<QListWidgetItem*>::iterator &end, Qt::SortOrder order, QListWidgetItem *item); - void itemChanged(QListWidgetItem *item); + void itemChanged(QListWidgetItem *item, const QVector<int> &roles = QVector<int>()); // dnd QStringList mimeTypes() const override; diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp index 853e27cd6e..967b0b8dde 100644 --- a/src/widgets/kernel/qaction.cpp +++ b/src/widgets/kernel/qaction.cpp @@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE */ static QString qt_strippedText(QString s) { - s.remove(QStringLiteral("...")); + s.remove(QLatin1String("...")); for (int i = 0; i < s.size(); ++i) { if (s.at(i) == QLatin1Char('&')) s.remove(i, 1); diff --git a/src/widgets/kernel/qlayout.h b/src/widgets/kernel/qlayout.h index abadf2e69d..bcc33a0811 100644 --- a/src/widgets/kernel/qlayout.h +++ b/src/widgets/kernel/qlayout.h @@ -126,8 +126,8 @@ public: bool isEmpty() const override; QSizePolicy::ControlTypes controlTypes() const override; - // ### Qt 6 make this function virtual - QLayoutItem *replaceWidget(QWidget *from, QWidget *to, Qt::FindChildOptions options = Qt::FindChildrenRecursively); + QT6_VIRTUAL QLayoutItem *replaceWidget(QWidget *from, QWidget *to, + Qt::FindChildOptions options = Qt::FindChildrenRecursively); int totalHeightForWidth(int w) const; QSize totalMinimumSize() const; diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 12b60c634c..670a23e78f 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -743,8 +743,9 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q % QLatin1String(metaObject()->className()), opt, QSize(size, size)) % HexString<uint>(pe); if (!QPixmapCache::find(pixmapName, pixmap)) { - int border = size/5; - int sqsize = 2*(size/2); + qreal pixelRatio = p->device()->devicePixelRatioF(); + int border = qRound(pixelRatio*(size/5)); + int sqsize = qRound(pixelRatio*(2*(size/2))); QImage image(sqsize, sqsize, QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter imagePainter(&image); @@ -796,6 +797,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q imagePainter.drawPolygon(a); imagePainter.end(); pixmap = QPixmap::fromImage(image); + pixmap.setDevicePixelRatio(pixelRatio); QPixmapCache::insert(pixmapName, pixmap); } int xOffset = r.x() + (r.width() - size)/2; @@ -1581,10 +1583,11 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, aligned.width() * pixmap.devicePixelRatio(), pixmap.height() * pixmap.devicePixelRatio()); + const int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget); if (header->direction == Qt::LeftToRight) - rect.setLeft(rect.left() + pixw + 2); + rect.setLeft(rect.left() + pixw + margin); else - rect.setRight(rect.right() - pixw - 2); + rect.setRight(rect.right() - pixw - margin); } if (header->state & QStyle::State_On) { QFont fnt = p->font(); @@ -4165,14 +4168,10 @@ QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex #if QT_CONFIG(combobox) case CC_ComboBox: if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) { - int x = cb->rect.x(), - y = cb->rect.y(), - wi = cb->rect.width(), - he = cb->rect.height(); - int xpos = x; - int margin = cb->frame ? 3 : 0; - int bmarg = cb->frame ? 2 : 0; - xpos += wi - bmarg - 16; + const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height(); + const int margin = cb->frame ? qRound(QStyleHelper::dpiScaled(3)) : 0; + const int bmarg = cb->frame ? qRound(QStyleHelper::dpiScaled(2)) : 0; + const int xpos = x + wi - bmarg - qRound(QStyleHelper::dpiScaled(16)); switch (sc) { @@ -4180,10 +4179,10 @@ QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex ret = cb->rect; break; case SC_ComboBoxArrow: - ret.setRect(xpos, y + bmarg, 16, he - 2*bmarg); + ret.setRect(xpos, y + bmarg, qRound(QStyleHelper::dpiScaled(16)), he - 2*bmarg); break; case SC_ComboBoxEditField: - ret.setRect(x + margin, y + margin, wi - 2 * margin - 16, he - 2 * margin); + ret.setRect(x + margin, y + margin, wi - 2 * margin - qRound(QStyleHelper::dpiScaled(16)), he - 2 * margin); break; case SC_ComboBoxListBoxPopup: ret = cb->rect; diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index a2b94d59d4..26f651906a 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -2737,6 +2737,8 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption pixmapName += QLatin1String("-editable"); if (isEnabled) pixmapName += QLatin1String("-enabled"); + if (!comboBox->frame) + pixmapName += QLatin1String("-frameless"); if (!QPixmapCache::find(pixmapName, cache)) { cache = styleCachePixmap(comboBox->rect.size()); @@ -2762,7 +2764,8 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption buttonOption.state &= ~State_MouseOver; } - proxy()->drawPrimitive(PE_FrameLineEdit, &buttonOption, &cachePainter, widget); + if (comboBox->frame) + proxy()->drawPrimitive(PE_FrameLineEdit, &buttonOption, &cachePainter, widget); // Draw button clipped cachePainter.save(); diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 7a84a4dcf8..89011350ec 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -798,9 +798,10 @@ void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, break; case PE_FrameDefaultButton: { QPen oldPen = p->pen(); - p->setPen(opt->palette.shadow().color()); - QRect rect = opt->rect; - rect.adjust(0, 0, -1, -1); + p->setPen(QPen(opt->palette.shadow().color(), 0)); + QRectF rect = opt->rect; + rect.adjust(QStyleHelper::dpiScaled(0.5), QStyleHelper::dpiScaled(0.5), + QStyleHelper::dpiScaled(-1.5), QStyleHelper::dpiScaled(-1.5)); p->drawRect(rect); p->setPen(oldPen); break; @@ -843,22 +844,16 @@ void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, } #endif // QT_CONFIG(itemviews) if (!(opt->state & State_Off)) { - QLineF lines[7]; - int i, xx, yy; - xx = opt->rect.x() + 3; - yy = opt->rect.y() + 5; - for (i = 0; i < 3; ++i) { - lines[i] = QLineF(xx, yy, xx, yy + 2); - ++xx; - ++yy; - } - yy -= 2; - for (i = 3; i < 7; ++i) { - lines[i] = QLineF(xx, yy, xx, yy + 2); - ++xx; - --yy; - } - p->drawLines(lines, 7); + QPointF points[6]; + points[0] = { opt->rect.x() + QStyleHelper::dpiScaled(3.5), opt->rect.y() + QStyleHelper::dpiScaled(5.5) }; + points[1] = { points[0].x(), points[0].y() + QStyleHelper::dpiScaled(2) }; + points[2] = { points[1].x() + QStyleHelper::dpiScaled(2), points[1].y() + QStyleHelper::dpiScaled(2) }; + points[3] = { points[2].x() + QStyleHelper::dpiScaled(4), points[2].y() - QStyleHelper::dpiScaled(4) }; + points[4] = { points[3].x(), points[3].y() - QStyleHelper::dpiScaled(2) }; + points[5] = { points[4].x() - QStyleHelper::dpiScaled(4), points[4].y() + QStyleHelper::dpiScaled(4) }; + p->setPen(QPen(opt->palette.text().color(), 0)); + p->setBrush(opt->palette.text().color()); + p->drawPolygon(points, 6); } if (doRestore) p->restore(); @@ -890,86 +885,57 @@ void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, break; case PE_IndicatorRadioButton: { -#define PTSARRLEN(x) sizeof(x)/(sizeof(QPoint)) - static const QPoint pts1[] = { // dark lines - QPoint(1, 9), QPoint(1, 8), QPoint(0, 7), QPoint(0, 4), QPoint(1, 3), QPoint(1, 2), - QPoint(2, 1), QPoint(3, 1), QPoint(4, 0), QPoint(7, 0), QPoint(8, 1), QPoint(9, 1) - }; - static const QPoint pts2[] = { // black lines - QPoint(2, 8), QPoint(1, 7), QPoint(1, 4), QPoint(2, 3), QPoint(2, 2), QPoint(3, 2), - QPoint(4, 1), QPoint(7, 1), QPoint(8, 2), QPoint(9, 2) - }; - static const QPoint pts3[] = { // background lines - QPoint(2, 9), QPoint(3, 9), QPoint(4, 10), QPoint(7, 10), QPoint(8, 9), QPoint(9, 9), - QPoint(9, 8), QPoint(10, 7), QPoint(10, 4), QPoint(9, 3) - }; - static const QPoint pts4[] = { // white lines - QPoint(2, 10), QPoint(3, 10), QPoint(4, 11), QPoint(7, 11), QPoint(8, 10), - QPoint(9, 10), QPoint(10, 9), QPoint(10, 8), QPoint(11, 7), QPoint(11, 4), - QPoint(10, 3), QPoint(10, 2) - }; - static const QPoint pts5[] = { // inner fill - QPoint(4, 2), QPoint(7, 2), QPoint(9, 4), QPoint(9, 7), QPoint(7, 9), QPoint(4, 9), - QPoint(2, 7), QPoint(2, 4) - }; - - // make sure the indicator is square - QRect ir = opt->rect; - - if (opt->rect.width() < opt->rect.height()) { - ir.setTop(opt->rect.top() + (opt->rect.height() - opt->rect.width()) / 2); - ir.setHeight(opt->rect.width()); - } else if (opt->rect.height() < opt->rect.width()) { - ir.setLeft(opt->rect.left() + (opt->rect.width() - opt->rect.height()) / 2); - ir.setWidth(opt->rect.height()); - } - + QRect r = opt->rect; p->save(); - p->setRenderHint(QPainter::Qt4CompatiblePainting); - bool down = opt->state & State_Sunken; - bool enabled = opt->state & State_Enabled; - bool on = opt->state & State_On; - QPolygon a; - - //center when rect is larger than indicator size - int xOffset = 0; - int yOffset = 0; - int indicatorWidth = proxy()->pixelMetric(PM_ExclusiveIndicatorWidth); - int indicatorHeight = proxy()->pixelMetric(PM_ExclusiveIndicatorHeight); - if (ir.width() > indicatorWidth) - xOffset += (ir.width() - indicatorWidth)/2; - if (ir.height() > indicatorHeight) - yOffset += (ir.height() - indicatorHeight)/2; - p->translate(xOffset, yOffset); - - p->translate(ir.x(), ir.y()); - + p->setRenderHint(QPainter::Antialiasing, true); + + QPointF circleCenter = r.center() + QPoint(1, 1); + qreal radius = (r.width() + (r.width() + 1) % 2) / 2.0 - 1; + + QPainterPath path1; + path1.addEllipse(circleCenter, radius, radius); + radius *= 0.85; + QPainterPath path2; + path2.addEllipse(circleCenter, radius, radius); + radius *= 0.85; + QPainterPath path3; + path3.addEllipse(circleCenter, radius, radius); + radius *= 0.5; + QPainterPath path4; + path4.addEllipse(circleCenter, radius, radius); + + QPolygon topLeftPol, bottomRightPol; + topLeftPol.setPoints(3, r.x(), r.y(), r.x(), r.y() + r.height(), r.x() + r.width(), r.y()); + bottomRightPol.setPoints(3, r.x(), r.y() + r.height(), r.x() + r.width(), r.y() + r.height(), r.x() + r.width(), r.y()); + + p->setClipRegion(QRegion(topLeftPol)); p->setPen(opt->palette.dark().color()); - p->drawPolyline(pts1, PTSARRLEN(pts1)); - + p->setBrush(opt->palette.dark().color()); + p->drawPath(path1); p->setPen(opt->palette.shadow().color()); - p->drawPolyline(pts2, PTSARRLEN(pts2)); + p->setBrush(opt->palette.shadow().color()); + p->drawPath(path2); + p->setClipRegion(QRegion(bottomRightPol)); + p->setPen(opt->palette.light().color()); + p->setBrush(opt->palette.light().color()); + p->drawPath(path1); p->setPen(opt->palette.midlight().color()); - p->drawPolyline(pts3, PTSARRLEN(pts3)); + p->setBrush(opt->palette.midlight().color()); + p->drawPath(path2); - p->setPen(opt->palette.light().color()); - p->drawPolyline(pts4, PTSARRLEN(pts4)); + QColor fillColor = ((opt->state & State_Sunken) || !(opt->state & State_Enabled)) ? + opt->palette.button().color() : opt->palette.base().color(); - QColor fillColor = (down || !enabled) - ? opt->palette.button().color() - : opt->palette.base().color(); + p->setClipping(false); p->setPen(fillColor); - p->setBrush(fillColor) ; - p->drawPolygon(pts5, PTSARRLEN(pts5)); + p->setBrush(fillColor); + p->drawPath(path3); - p->translate(-ir.x(), -ir.y()); // restore translate - - if (on) { - p->setPen(Qt::NoPen); + if (opt->state & State_On) { + p->setPen(opt->palette.text().color()); p->setBrush(opt->palette.text()); - p->drawRect(ir.x() + 5, ir.y() + 4, 2, 4); - p->drawRect(ir.x() + 4, ir.y() + 5, 4, 2); + p->drawPath(path4); } p->restore(); break; diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index 156b0e331c..e3b348f0ef 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -1466,6 +1466,8 @@ bool QLineEdit::event(QEvent * e) #endif } else if (e->type() == QEvent::Resize) { d->positionSideWidgets(); + } else if (e->type() == QEvent::StyleChange) { + d->initMouseYThreshold(); } #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled()) { @@ -1546,7 +1548,17 @@ void QLineEdit::mouseMoveEvent(QMouseEvent * e) const bool select = (d->imHints & Qt::ImhNoPredictiveText); #endif #ifndef QT_NO_IM - if (d->control->composeMode() && select) { + if (d->mouseYThreshold > 0 && e->pos().y() > d->mousePressPos.y() + d->mouseYThreshold) { + if (layoutDirection() == Qt::RightToLeft) + d->control->home(select); + else + d->control->end(select); + } else if (d->mouseYThreshold > 0 && e->pos().y() + d->mouseYThreshold < d->mousePressPos.y()) { + if (layoutDirection() == Qt::RightToLeft) + d->control->end(select); + else + d->control->home(select); + } else if (d->control->composeMode() && select) { int startPos = d->xToPos(d->mousePressPos.x()); int currentPos = d->xToPos(e->pos().x()); if (startPos != currentPos) diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index c66b842223..6a8af53c97 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -56,6 +56,7 @@ #endif #include <qpainter.h> #include <qpropertyanimation.h> +#include <qstylehints.h> #include <qvalidator.h> QT_BEGIN_NAMESPACE @@ -232,6 +233,13 @@ void QLineEditPrivate::init(const QString& txt) q->setAcceptDrops(true); q->setAttribute(Qt::WA_MacShowFocusRect); + + initMouseYThreshold(); +} + +void QLineEditPrivate::initMouseYThreshold() +{ + mouseYThreshold = QGuiApplication::styleHints()->mouseQuickSelectionThreshold(); } QRect QLineEditPrivate::adjustedContentsRect() const diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h index a3f549ad31..39f670b0b0 100644 --- a/src/widgets/widgets/qlineedit_p.h +++ b/src/widgets/widgets/qlineedit_p.h @@ -141,7 +141,7 @@ public: dragEnabled(0), clickCausedFocus(0), hscroll(0), vscroll(0), alignment(Qt::AlignLeading | Qt::AlignVCenter), leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0), - lastTextSize(0) + lastTextSize(0), mouseYThreshold(0) { } @@ -155,6 +155,7 @@ public: QPointer<QAction> selectAllAction; #endif void init(const QString&); + void initMouseYThreshold(); QRect adjustedControlRect(const QRect &) const; @@ -253,6 +254,7 @@ private: SideWidgetEntryList leadingSideWidgets; SideWidgetEntryList trailingSideWidgets; int lastTextSize; + int mouseYThreshold; }; Q_DECLARE_TYPEINFO(QLineEditPrivate::SideWidgetEntry, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QLineEditPrivate::SideWidgetLocation, Q_PRIMITIVE_TYPE); diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 0c11afdc61..b0a75288e8 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1080,6 +1080,10 @@ void QMenuBar::mouseReleaseEvent(QMouseEvent *e) d->mouseDown = false; QAction *action = d->actionAt(e->pos()); + + // do noting if the action is hidden + if (!d->isVisible(action)) + return; if((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) { //we set the current action before activating //so that we let the leave event set the current back to 0 diff --git a/src/xml/sax/qxml.h b/src/xml/sax/qxml.h index 7c5b5fe204..94dc8dfb8e 100644 --- a/src/xml/sax/qxml.h +++ b/src/xml/sax/qxml.h @@ -122,10 +122,8 @@ public: QXmlAttributes &operator=(const QXmlAttributes &) = default; QXmlAttributes &operator=(QXmlAttributes &&) Q_DECL_NOTHROW = default; #endif // default members -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - virtual // ### Qt 6: this value class don't need no virtual dtor -#endif - ~QXmlAttributes(); + + QT6_NOT_VIRTUAL ~QXmlAttributes(); void swap(QXmlAttributes &other) Q_DECL_NOTHROW { |