diff --git a/examples/widgets/doc/src/shapedclock.qdoc b/examples/widgets/doc/src/shapedclock.qdoc index 2e5d8b1496..732820cdc8 100644 --- a/examples/widgets/doc/src/shapedclock.qdoc +++ b/examples/widgets/doc/src/shapedclock.qdoc @@ -29,16 +29,18 @@ \example widgets/shapedclock \title Shaped Clock Example \ingroup examples-widgets - \brief The Shaped Clock example shows how to apply a widget mask to a top-level - widget to produce a shaped window. + \brief The Shaped Clock example shows how to apply a translucent background + and a widget mask to a top-level widget to produce a shaped window. \borderedimage shapedclock-example.png - Widget masks are used to customize the shapes of top-level widgets by restricting - the available area for painting. On some window systems, setting certain window flags - will cause the window decoration (title bar, window frame, buttons) to be disabled, - allowing specially-shaped windows to be created. In this example, we use this feature - to create a circular window containing an analog clock. + Widget masks are used to customize the shapes of top-level widgets by + restricting the area available for painting and mouse input. Using a + translucent background facilitates partially transparent windows and smooth + edges. On most window systems, setting certain window flags will cause the + window decoration (title bar, window frame, buttons) to be disabled, + allowing specially-shaped windows to be created. In this example, we use + this feature to create a circular window containing an analog clock. Since this example's window does not provide a \uicontrol File menu or a close button, we provide a context menu with an \uicontrol Exit entry so that the example @@ -52,8 +54,10 @@ \snippet widgets/shapedclock/shapedclock.h 0 - The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as that found - in the \c AnalogClock class. We implement \l{QWidget::sizeHint()}{sizeHint()} + The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as + that found in the \c AnalogClock class, with one important exception: we + now must also draw background (the clock face) ourselves, since the widget + background is just transparent. We implement \l{QWidget::sizeHint()}{sizeHint()} so that we don't have to resize the widget explicitly. We also provide an event handler for resize events. This allows us to update the mask if the clock is resized. @@ -70,9 +74,11 @@ \snippet widgets/shapedclock/shapedclock.cpp 0 - We inform the window manager that the widget is not to be decorated with a window - frame by setting the Qt::FramelessWindowHint flag on the widget. As a result, we need - to provide a way for the user to move the clock around the screen. + We request a transparent window by setting the Qt::WA_TranslucentBackground + widget attribute. We inform the window manager that the widget is not to be + decorated with a window frame by setting the Qt::FramelessWindowHint flag + on the widget. As a result, we need to provide a way for the user to move + the clock around the screen. Mouse button events are delivered to the \c mousePressEvent() handler: @@ -94,14 +100,20 @@ widget is moved to the point given by subtracting the \c dragPosition from the current cursor position in global coordinates. If we drag the widget, we also accept the event. - The \c paintEvent() function is given for completeness. See the - \l{Analog Clock Example}{Analog Clock} example for a description of the process used - to render the clock. + The \c paintEvent() function is mainly the same as described in the + \l{Analog Clock Example}{Analog Clock} example. The one addition is that we + use QPainter::drawEllipse() to draw a round clock face with the current + palette's default background color. We make the clock face a bit smaller + than the widget mask, so that the anti-aliased, semi-transparent pixels on + the edge are not clipped away by the widget mask. This gives the shaped + window smooth edges on the screen. \snippet widgets/shapedclock/shapedclock.cpp 3 - In the \c resizeEvent() handler, we re-use some of the code from the \c paintEvent() - to determine the region of the widget that is visible to the user: + In the \c resizeEvent() handler, we re-use some of the code from the \c + paintEvent() to determine the region of the widget that is visible to the + user. This tells the system the area where mouse clicks should go to us, + and not to whatever window is behind us: \snippet widgets/shapedclock/shapedclock.cpp 4 @@ -121,6 +133,12 @@ \section1 Notes on Widget Masks + Widget masks are used to hint to the window system that the application + does not want mouse events for areas outside the mask. On most systems, + they also result in coarse visual clipping. To get smooth window edges, one + should use translucent background and anti-aliased painting, as shown in + this example. + Since QRegion allows arbitrarily complex regions to be created, widget masks can be made to suit the most unconventionally-shaped windows, and even allow widgets to be displayed with holes in them. diff --git a/examples/widgets/widgets/shapedclock/shapedclock.cpp b/examples/widgets/widgets/shapedclock/shapedclock.cpp index 3c78f4da89..673d1a218f 100644 --- a/examples/widgets/widgets/shapedclock/shapedclock.cpp +++ b/examples/widgets/widgets/shapedclock/shapedclock.cpp @@ -61,6 +61,7 @@ ShapedClock::ShapedClock(QWidget *parent) : QWidget(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint) { + setAttribute(Qt::WA_TranslucentBackground); QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, QOverload<>::of(&ShapedClock::update)); timer->start(1000); @@ -122,6 +123,10 @@ void ShapedClock::paintEvent(QPaintEvent *) painter.translate(width() / 2, height() / 2); painter.scale(side / 200.0, side / 200.0); + painter.setPen(Qt::NoPen); + painter.setBrush(palette().window()); + painter.drawEllipse(QPoint(0, 0), 98, 98); + painter.setPen(Qt::NoPen); painter.setBrush(hourColor); @@ -168,6 +173,6 @@ void ShapedClock::resizeEvent(QResizeEvent * /* event */) //! [5] QSize ShapedClock::sizeHint() const { - return QSize(100, 100); + return QSize(200, 200); } //! [5] diff --git a/mkspecs/features/wasm/wasm.prf b/mkspecs/features/wasm/wasm.prf index 25413d7470..5773e58010 100644 --- a/mkspecs/features/wasm/wasm.prf +++ b/mkspecs/features/wasm/wasm.prf @@ -71,7 +71,7 @@ contains(TEMPLATE, .*app) { # replacing the app name placeholder with the actual app name. apphtml.name = application main html file apphtml.output = $$DESTDIR/$$TARGET_HTML - apphtml.commands = sed -e s/@APPNAME@/$$TARGET_BASE/g $$WASM_PLUGIN_PATH/wasm_shell.html > $$DESTDIR/$$TARGET_HTML + apphtml.commands = $$QMAKE_STREAM_EDITOR -e s/@APPNAME@/$$TARGET_BASE/g $$WASM_PLUGIN_PATH/wasm_shell.html > $$DESTDIR/$$TARGET_HTML apphtml.input = $$WASM_PLUGIN_PATH/wasm_shell.html apphtml.depends = $$apphtml.input QMAKE_EXTRA_COMPILERS += apphtml diff --git a/mkspecs/wasm-emscripten/qmake.conf b/mkspecs/wasm-emscripten/qmake.conf index c69ed9af79..919dcfb214 100644 --- a/mkspecs/wasm-emscripten/qmake.conf +++ b/mkspecs/wasm-emscripten/qmake.conf @@ -25,7 +25,7 @@ EMTERP_FLAGS = \ -s ASSERTIONS=1 \ --profiling-funcs -EMCC_COMMON_LFLAGS = \ +EMCC_COMMON_LFLAGS += \ -s WASM=1 \ -s FULL_ES2=1 \ -s FULL_ES3=1 \ diff --git a/qmake/main.cpp b/qmake/main.cpp index dd1cca9633..86f91031df 100644 --- a/qmake/main.cpp +++ b/qmake/main.cpp @@ -154,7 +154,7 @@ static int doSed(int argc, char **argv) FILE *f; if (!strcmp(inFile, "-")) { f = stdin; - } else if (!(f = fopen(inFile, "r"))) { + } else if (!(f = fopen(inFile, "rb"))) { perror(inFile); return 1; } diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index 7cfbe1273f..fedf08301f 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -492,6 +492,39 @@ # error "Qt has not been tested with this compiler - see http://www.qt-project.org/" #endif +/* + * SG10's SD-6 feature detection and some useful extensions from Clang and GCC + * https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations + * http://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros + * Not using wrapper macros, per http://eel.is/c++draft/cpp.cond#7.sentence-2 + */ +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif +#ifndef __has_feature +# define __has_feature(x) 0 +#endif +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif +#ifndef __has_cpp_attribute +# define __has_cpp_attribute(x) 0 +#endif +#ifndef __has_include +# define __has_include(x) 0 +#endif +#ifndef __has_include_next +# define __has_include_next(x) 0 +#endif + +// Kept around until all submodules have transitioned +#define QT_HAS_BUILTIN(x) __has_builtin(x) +#define QT_HAS_FEATURE(x) __has_feature(x) +#define QT_HAS_ATTRIBUTE(x) __has_attribute(x) +#define QT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#define QT_HAS_INCLUDE(x) __has_include(x) +#define QT_HAS_INCLUDE_NEXT(x) __has_include_next(x) + /* * C++11 support * @@ -1018,37 +1051,6 @@ # endif #endif -/* - * SG10's SD-6 feature detection and some useful extensions from Clang and GCC - * https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations - * http://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros - */ -#ifdef __has_builtin -# define QT_HAS_BUILTIN(x) __has_builtin(x) -#else -# define QT_HAS_BUILTIN(x) 0 -#endif -#ifdef __has_attribute -# define QT_HAS_ATTRIBUTE(x) __has_attribute(x) -#else -# define QT_HAS_ATTRIBUTE(x) 0 -#endif -#ifdef __has_cpp_attribute -# define QT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define QT_HAS_CPP_ATTRIBUTE(x) 0 -#endif -#ifdef __has_include -# define QT_HAS_INCLUDE(x) __has_include(x) -#else -# define QT_HAS_INCLUDE(x) 0 -#endif -#ifdef __has_include_next -# define QT_HAS_INCLUDE_NEXT(x) __has_include_next(x) -#else -# define QT_HAS_INCLUDE_NEXT(x) 0 -#endif - /* * C++11 keywords and expressions */ @@ -1123,7 +1125,7 @@ # define Q_DECL_ALIGN(n) alignas(n) #endif -#if QT_HAS_CPP_ATTRIBUTE(nodiscard) && !defined(Q_CC_CLANG) // P0188R1 +#if __has_cpp_attribute(nodiscard) && !defined(Q_CC_CLANG) // P0188R1 // Can't use [[nodiscard]] with Clang, see https://bugs.llvm.org/show_bug.cgi?id=33518 # undef Q_REQUIRED_RESULT # define Q_REQUIRED_RESULT [[nodiscard]] @@ -1225,11 +1227,6 @@ #ifndef QT_MAKE_CHECKED_ARRAY_ITERATOR # define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) (x) #endif -#ifdef __has_feature -# define QT_HAS_FEATURE(x) __has_feature(x) -#else -# define QT_HAS_FEATURE(x) 0 -#endif /* * Warning/diagnostic handling @@ -1320,11 +1317,11 @@ } while (false) #if defined(__cplusplus) -#if QT_HAS_CPP_ATTRIBUTE(clang::fallthrough) +#if __has_cpp_attribute(clang::fallthrough) # define Q_FALLTHROUGH() [[clang::fallthrough]] -#elif QT_HAS_CPP_ATTRIBUTE(gnu::fallthrough) +#elif __has_cpp_attribute(gnu::fallthrough) # define Q_FALLTHROUGH() [[gnu::fallthrough]] -#elif QT_HAS_CPP_ATTRIBUTE(fallthrough) +#elif __has_cpp_attribute(fallthrough) # define Q_FALLTHROUGH() [[fallthrough]] #endif #endif diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h index c58dc56c42..2e6c3fbb20 100644 --- a/src/corelib/global/qconfig-bootstrapped.h +++ b/src/corelib/global/qconfig-bootstrapped.h @@ -77,13 +77,13 @@ #define QT_FEATURE_binaryjson -1 #define QT_FEATURE_cborstream -1 #define QT_CRYPTOGRAPHICHASH_ONLY_SHA1 -#define QT_FEATURE_cxx11_random (QT_HAS_INCLUDE() ? 1 : -1) +#define QT_FEATURE_cxx11_random (__has_include() ? 1 : -1) #define QT_NO_DATASTREAM #define QT_FEATURE_datestring 1 #define QT_FEATURE_datetimeparser -1 #define QT_FEATURE_easingcurve -1 #define QT_FEATURE_etw -1 -#define QT_FEATURE_getauxval (QT_HAS_INCLUDE() ? 1 : -1) +#define QT_FEATURE_getauxval (__has_include() ? 1 : -1) #define QT_FEATURE_getentropy -1 #define QT_NO_GEOM_VARIANT #define QT_FEATURE_hijricalendar -1 diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h index 5cd9d3160b..257efbbdbe 100644 --- a/src/corelib/global/qendian.h +++ b/src/corelib/global/qendian.h @@ -66,7 +66,7 @@ template Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest) // Using sizeof(T) inside memcpy function produces internal compiler error with // MSVC2008/ARM in tst_endian -> use extra indirection to resolve size of T. const size_t size = sizeof(T); -#if QT_HAS_BUILTIN(__builtin_memcpy) +#if __has_builtin(__builtin_memcpy) __builtin_memcpy #else memcpy @@ -78,7 +78,7 @@ template Q_ALWAYS_INLINE T qFromUnaligned(const void *src) { T dest; const size_t size = sizeof(T); -#if QT_HAS_BUILTIN(__builtin_memcpy) +#if __has_builtin(__builtin_memcpy) __builtin_memcpy #else memcpy diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 554c24356b..c2c91df756 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -92,7 +92,7 @@ # include #endif -#if defined(Q_OS_DARWIN) && QT_HAS_INCLUDE() +#if defined(Q_OS_DARWIN) && __has_include() # include # include #endif @@ -3067,7 +3067,7 @@ enum { */ QByteArray QSysInfo::machineUniqueId() { -#if defined(Q_OS_DARWIN) && QT_HAS_INCLUDE() +#if defined(Q_OS_DARWIN) && __has_include() char uuid[UuidStringLen + 1]; io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 4dc63cae5e..80433ebeff 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -717,7 +717,7 @@ inline void qt_noop(void) {} #if !defined(QT_NO_EXCEPTIONS) # if !defined(Q_MOC_RUN) -# if (defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !QT_HAS_FEATURE(cxx_exceptions)) || \ +# if (defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !__has_feature(cxx_exceptions)) || \ (defined(Q_CC_GNU) && !defined(__EXCEPTIONS)) # define QT_NO_EXCEPTIONS # endif diff --git a/src/corelib/global/qglobal_p.h b/src/corelib/global/qglobal_p.h index 58bc8b7bf3..5ab84fa8be 100644 --- a/src/corelib/global/qglobal_p.h +++ b/src/corelib/global/qglobal_p.h @@ -74,7 +74,7 @@ Q_CORE_EXPORT time_t qMkTime(struct tm *when); QT_END_NAMESPACE -#if !QT_HAS_BUILTIN(__builtin_available) +#if !__has_builtin(__builtin_available) #include #include #include @@ -142,7 +142,7 @@ QT_END_NAMESPACE QT_BUILTIN_AVAILABLE1, \ QT_BUILTIN_AVAILABLE0, ) #define __builtin_available(...) QT_BUILTIN_AVAILABLE_CHOOSER(__VA_ARGS__)(__VA_ARGS__) -#endif // !QT_HAS_BUILTIN(__builtin_available) +#endif // !__has_builtin(__builtin_available) #endif // defined(__cplusplus) #endif // QGLOBAL_P_H diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index e011645605..ca4d8dbd11 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -70,7 +70,7 @@ #if QT_CONFIG(slog2) #include #endif -#if QT_HAS_INCLUDE() +#if __has_include() #include #endif @@ -106,7 +106,7 @@ # if __UCLIBC_HAS_BACKTRACE__ # define QLOGGING_HAVE_BACKTRACE # endif -# elif (defined(__GLIBC__) && defined(__GLIBCXX__)) || (QT_HAS_INCLUDE() && QT_HAS_INCLUDE()) +# elif (defined(__GLIBC__) && defined(__GLIBCXX__)) || (__has_include() && __has_include()) # define QLOGGING_HAVE_BACKTRACE # endif #endif @@ -116,7 +116,7 @@ extern char *__progname; #endif #ifndef QT_BOOTSTRAPPED -#if defined(Q_OS_LINUX) && (defined(__GLIBC__) || QT_HAS_INCLUDE()) +#if defined(Q_OS_LINUX) && (defined(__GLIBC__) || __has_include()) # include # if defined(Q_OS_ANDROID) && !defined(SYS_gettid) @@ -1276,7 +1276,7 @@ void QMessagePattern::setPattern(const QString &pattern) #if defined(QLOGGING_HAVE_BACKTRACE) && !defined(QT_BOOTSTRAPPED) // make sure the function has "Message" in the name so the function is removed -#if ((defined(Q_CC_GNU) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) || QT_HAS_ATTRIBUTE(optimize)) \ +#if ((defined(Q_CC_GNU) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) || __has_attribute(optimize)) \ && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) // force skipping the frame pointer, to save the backtrace() function some work __attribute__((optimize("omit-frame-pointer"))) diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index c006296b3d..376da66e31 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -253,7 +253,7 @@ QT_WARNING_POP // 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) && !defined(Q_OS_WIN))) || QT_HAS_BUILTIN(__builtin_add_overflow) +#if (defined(Q_CC_GNU) && (Q_CC_GNU >= 500) || (defined(Q_CC_INTEL) && !defined(Q_OS_WIN))) || __has_builtin(__builtin_add_overflow) // GCC 5, ICC 18, and Clang 3.8 have builtins to detect overflows template inline diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 2e81f93bcf..3bbebc7fe9 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -55,7 +55,7 @@ #include #include -#if QT_HAS_INCLUDE() +#if __has_include() # include #endif #ifndef _PATH_TMP // from diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index ad2e7fb6b8..816026a36c 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -100,7 +100,7 @@ QT_END_NAMESPACE #include #endif -#if QT_HAS_INCLUDE() +#if __has_include() #include #endif diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index b62dc24b47..a5128a868b 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -48,7 +48,7 @@ #include #endif -#if QT_HAS_INCLUDE() +#if __has_include() #include #endif diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 1e72241e68..37b8a60c37 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -108,7 +108,7 @@ # endif // QT_LARGEFILE_SUPPORT #endif // Q_OS_BSD4 -#if QT_HAS_INCLUDE() +#if __has_include() # include #endif #ifndef _PATH_MOUNTED diff --git a/src/corelib/kernel/qdeadlinetimer.h b/src/corelib/kernel/qdeadlinetimer.h index 9dd92481d2..99e09eb31f 100644 --- a/src/corelib/kernel/qdeadlinetimer.h +++ b/src/corelib/kernel/qdeadlinetimer.h @@ -52,7 +52,7 @@ #include -#if QT_HAS_INCLUDE() +#if __has_include() # include #endif @@ -120,7 +120,7 @@ public: QDeadlineTimer &operator-=(qint64 msecs) { *this = *this + (-msecs); return *this; } -#if QT_HAS_INCLUDE() || defined(Q_CLANG_QDOC) +#if __has_include() || defined(Q_CLANG_QDOC) template QDeadlineTimer(std::chrono::time_point deadline_, Qt::TimerType type_ = Qt::CoarseTimer) : t2(0) diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index ca5275a3ac..8d9cc3ab83 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -55,7 +55,7 @@ #include -#if QT_HAS_INCLUDE() +#if __has_include() # include #endif @@ -154,7 +154,7 @@ public: void moveToThread(QThread *thread); int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer); -#if QT_HAS_INCLUDE() +#if __has_include() Q_ALWAYS_INLINE int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer) { diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index eb7185c12d..6bbfd741d9 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -47,7 +47,7 @@ #include // conceptual inheritance #include -#if QT_HAS_INCLUDE() +#if __has_include() # include #endif @@ -177,7 +177,7 @@ Q_SIGNALS: void timeout(QPrivateSignal); public: -#if QT_HAS_INCLUDE() || defined(Q_QDOC) +#if __has_include() || defined(Q_QDOC) void setInterval(std::chrono::milliseconds value) { setInterval(int(value.count())); @@ -223,7 +223,7 @@ private: static void singleShotImpl(int msec, Qt::TimerType timerType, const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj); -#if QT_HAS_INCLUDE() +#if __has_include() static Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval) { return defaultTypeFor(int(interval.count())); } diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 0457b6fbad..24c7bd44dd 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -53,7 +53,7 @@ #include #endif -#if QT_HAS_INCLUDE() && __cplusplus >= 201703L +#if __has_include() && __cplusplus >= 201703L #include #elif defined(Q_CLANG_QDOC) namespace std { template struct variant; } @@ -372,7 +372,7 @@ class Q_CORE_EXPORT QVariant static inline QVariant fromValue(const T &value) { return QVariant(qMetaTypeId(), &value, QTypeInfo::isPointer); } -#if (QT_HAS_INCLUDE() && __cplusplus >= 201703L) || defined(Q_CLANG_QDOC) +#if (__has_include() && __cplusplus >= 201703L) || defined(Q_CLANG_QDOC) template static inline QVariant fromStdVariant(const std::variant &value) { @@ -538,7 +538,7 @@ inline QVariant QVariant::fromValue(const QVariant &value) return value; } -#if QT_HAS_INCLUDE() && __cplusplus >= 201703L +#if __has_include() && __cplusplus >= 201703L template<> inline QVariant QVariant::fromValue(const std::monostate &) { diff --git a/src/corelib/serialization/qcborarray.h b/src/corelib/serialization/qcborarray.h index e06544f245..fe06b8630f 100644 --- a/src/corelib/serialization/qcborarray.h +++ b/src/corelib/serialization/qcborarray.h @@ -214,7 +214,7 @@ public: bool contains(const QCborValue &value) const; int compare(const QCborArray &other) const noexcept Q_DECL_PURE_FUNCTION; -#if 0 && QT_HAS_INCLUDE() +#if 0 && __has_include() std::strong_ordering operator<=>(const QCborArray &other) const { int c = compare(other); diff --git a/src/corelib/serialization/qcbormap.h b/src/corelib/serialization/qcbormap.h index 4aea901eef..6636ce776a 100644 --- a/src/corelib/serialization/qcbormap.h +++ b/src/corelib/serialization/qcbormap.h @@ -245,7 +245,7 @@ public: { const_iterator it = find(key); return it != end(); } int compare(const QCborMap &other) const noexcept Q_DECL_PURE_FUNCTION; -#if 0 && QT_HAS_INCLUDE() +#if 0 && __has_include() std::strong_ordering operator<=>(const QCborMap &other) const { int c = compare(other); diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h index 9c613dfcfb..071213e83a 100644 --- a/src/corelib/serialization/qcborvalue.h +++ b/src/corelib/serialization/qcborvalue.h @@ -59,7 +59,7 @@ # undef False #endif -#if 0 && QT_HAS_INCLUDE() +#if 0 && __has_include() # include #endif @@ -265,7 +265,7 @@ public: QCborValueRef operator[](const QString & key); int compare(const QCborValue &other) const; -#if 0 && QT_HAS_INCLUDE() +#if 0 && __has_include() std::strong_ordering operator<=>(const QCborValue &other) const { int c = compare(other); @@ -421,7 +421,7 @@ public: int compare(const QCborValue &other) const { return concrete().compare(other); } -#if 0 && QT_HAS_INCLUDE() +#if 0 && __has_include() std::strong_ordering operator<=>(const QCborValue &other) const { int c = compare(other); diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h index b5d3de74fe..53ba81fa18 100644 --- a/src/corelib/serialization/qcborvalue_p.h +++ b/src/corelib/serialization/qcborvalue_p.h @@ -196,8 +196,7 @@ public: if (value.container) return replaceAt_complex(e, value, disp); - e.value = value.value_helper(); - e.type = value.type(); + e = { value.value_helper(), value.type() }; if (value.isContainer()) e.container = nullptr; } diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp index 83182dbd93..23296896b2 100644 --- a/src/corelib/text/qbytearray.cpp +++ b/src/corelib/text/qbytearray.cpp @@ -334,7 +334,7 @@ int qstricmp(const char *str1, const char *str2) return int(Incomplete); }; -#if defined(__SSE4_1__) && !(defined(__SANITIZE_ADDRESS__) || QT_HAS_FEATURE(address_sanitizer)) +#if defined(__SSE4_1__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)) enum { PageSize = 4096, PageMask = PageSize - 1 }; const __m128i zero = _mm_setzero_si128(); forever { diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h index fa87ebf058..863898f7e2 100644 --- a/src/corelib/text/qbytearray.h +++ b/src/corelib/text/qbytearray.h @@ -243,7 +243,7 @@ public: void chop(int n); #if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC) -# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !QT_HAS_CPP_ATTRIBUTE(nodiscard) +# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !__has_cpp_attribute(nodiscard) // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 # pragma push_macro("Q_REQUIRED_RESULT") # undef Q_REQUIRED_RESULT diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 0f313e21ed..e8ce637453 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -146,6 +146,9 @@ qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringVie static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept; template static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs) noexcept; +template <> +inline qsizetype qLastIndexOf(QString haystack, QChar needle, + qsizetype from, Qt::CaseSensitivity cs) noexcept = delete; // unwanted, would detach static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs); static inline qsizetype qt_string_count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs); @@ -3813,7 +3816,7 @@ int QString::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) co int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const { // ### Qt6: qsizetype - return int(QtPrivate::lastIndexOf(*this, from, str, cs)); + return int(QtPrivate::lastIndexOf(QStringView(*this), from, str, cs)); } #endif // QT_STRINGVIEW_LEVEL < 2 @@ -3852,7 +3855,7 @@ int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) co int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const { // ### Qt6: qsizetype - return int(qLastIndexOf(*this, ch, from, cs)); + return int(qLastIndexOf(QStringView(*this), ch, from, cs)); } #if QT_STRINGVIEW_LEVEL < 2 diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h index 27dc99b2e5..391e4788f2 100644 --- a/src/corelib/text/qstring.h +++ b/src/corelib/text/qstring.h @@ -485,7 +485,7 @@ public: Q_REQUIRED_RESULT QString rightJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const; #if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC) -# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !QT_HAS_CPP_ATTRIBUTE(nodiscard) +# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !__has_cpp_attribute(nodiscard) // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 # pragma push_macro("Q_REQUIRED_RESULT") # undef Q_REQUIRED_RESULT diff --git a/src/corelib/thread/qfutex_p.h b/src/corelib/thread/qfutex_p.h index 7bec4554b7..f287b752d7 100644 --- a/src/corelib/thread/qfutex_p.h +++ b/src/corelib/thread/qfutex_p.h @@ -81,7 +81,7 @@ QT_END_NAMESPACE // if not defined in linux/futex.h # define FUTEX_PRIVATE_FLAG 128 // added in v2.6.22 -# if QT_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) +# if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) # include inline void _q_tsan_acquire(void *addr, void *addr2) { @@ -98,7 +98,7 @@ inline void _q_tsan_release(void *addr, void *addr2) # else inline void _q_tsan_acquire(void *, void *) {} inline void _q_tsan_release(void *, void *) {} -# endif // QT_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) +# endif // __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__) QT_BEGIN_NAMESPACE namespace QtLinuxFutex { diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index c693ff65d8..93c4bf23e8 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -44,7 +44,7 @@ #include #include -#if QT_HAS_INCLUDE() +#if __has_include() # include # include #endif @@ -147,7 +147,7 @@ public: // Lockable concept bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); } -#if QT_HAS_INCLUDE() || defined(Q_CLANG_QDOC) +#if __has_include() || defined(Q_CLANG_QDOC) // TimedLockable concept template bool try_lock_for(std::chrono::duration duration) @@ -175,7 +175,7 @@ private: friend class QRecursiveMutex; friend class ::tst_QMutex; -#if QT_HAS_INCLUDE() +#if __has_include() template static int convertToMilliseconds(std::chrono::duration duration) { @@ -213,7 +213,7 @@ public: using QMutex::tryLock; using QMutex::unlock; using QMutex::try_lock; -#if QT_HAS_INCLUDE() +#if __has_include() using QMutex::try_lock_for; using QMutex::try_lock_until; #endif @@ -295,7 +295,7 @@ public: inline void unlock() noexcept {} inline bool isRecursive() const noexcept { return true; } -#if QT_HAS_INCLUDE() +#if __has_include() template inline bool try_lock_for(std::chrono::duration duration) noexcept { diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp index 979b8c9aeb..d2d09ceee6 100644 --- a/src/corelib/time/qdatetime.cpp +++ b/src/corelib/time/qdatetime.cpp @@ -127,7 +127,7 @@ static const char qt_shortMonthNames[][4] = { "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -static int qt_monthNumberFromShortName(QStringRef shortName) +static int qt_monthNumberFromShortName(QStringView shortName) { for (unsigned int i = 0; i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i) { if (shortName == QLatin1String(qt_shortMonthNames[i], 3)) @@ -136,9 +136,9 @@ static int qt_monthNumberFromShortName(QStringRef shortName) return -1; } static int qt_monthNumberFromShortName(const QString &shortName) -{ return qt_monthNumberFromShortName(QStringRef(&shortName)); } +{ return qt_monthNumberFromShortName(QStringView(shortName)); } -static int fromShortMonthName(const QStringRef &monthName, int year) +static int fromShortMonthName(QStringView monthName, int year) { // Assume that English monthnames are the default int month = qt_monthNumberFromShortName(monthName); @@ -207,7 +207,7 @@ static QString toOffsetString(Qt::DateFormat format, int offset) #if QT_CONFIG(datestring) // Parse offset in [+-]HH[[:]mm] format -static int fromOffsetString(const QStringRef &offsetString, bool *valid) noexcept +static int fromOffsetString(QStringView offsetString, bool *valid) noexcept { *valid = false; @@ -228,22 +228,23 @@ static int fromOffsetString(const QStringRef &offsetString, bool *valid) noexcep return 0; // Split the hour and minute parts - const QStringRef time = offsetString.mid(1); - int hhLen = time.indexOf(QLatin1Char(':')); - int mmIndex; + const QStringView time = offsetString.mid(1); + qsizetype hhLen = time.indexOf(QLatin1Char(':')); + qsizetype mmIndex; if (hhLen == -1) mmIndex = hhLen = 2; // [+-]HHmm or [+-]HH format else mmIndex = hhLen + 1; - const QStringRef hhRef = time.left(hhLen); + const QLocale C = QLocale::c(); + const QStringView hhRef = time.left(qMin(hhLen, time.size())); bool ok = false; - const int hour = hhRef.toInt(&ok); + const int hour = C.toInt(hhRef, &ok); if (!ok) return 0; - const QStringRef mmRef = time.mid(mmIndex); - const int minute = mmRef.isEmpty() ? 0 : mmRef.toInt(&ok); + const QStringView mmRef = time.mid(qMin(mmIndex, time.size())); + const int minute = mmRef.isEmpty() ? 0 : C.toInt(mmRef, &ok); if (!ok || minute < 0 || minute > 59) return 0; @@ -2324,7 +2325,7 @@ int QTime::msecsTo(const QTime &t) const #if QT_CONFIG(datestring) -static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format, bool *isMidnight24) +static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *isMidnight24) { if (isMidnight24) *isMidnight24 = false; @@ -2333,11 +2334,12 @@ static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format, if (size < 5) return QTime(); + const QLocale C(QLocale::c()); bool ok = false; - int hour = string.mid(0, 2).toInt(&ok); + int hour = C.toInt(string.mid(0, 2), &ok); if (!ok) return QTime(); - const int minute = string.mid(3, 2).toInt(&ok); + const int minute = C.toInt(string.mid(3, 2), &ok); if (!ok) return QTime(); int second = 0; @@ -2358,11 +2360,11 @@ static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format, // seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds // will then be rounded up AND clamped to 999. - const QStringRef minuteFractionStr = string.mid(6, 5); - const long minuteFractionInt = minuteFractionStr.toLong(&ok); + const QStringView minuteFractionStr = string.mid(6, qMin(qsizetype(5), string.size() - 6)); + const long minuteFractionInt = C.toLong(minuteFractionStr, &ok); if (!ok) return QTime(); - const float minuteFraction = double(minuteFractionInt) / (std::pow(double(10), minuteFractionStr.count())); + const float minuteFraction = double(minuteFractionInt) / (std::pow(double(10), minuteFractionStr.size())); const float secondWithMs = minuteFraction * 60; const float secondNoMs = std::floor(secondWithMs); @@ -2371,15 +2373,20 @@ static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format, msec = qMin(qRound(secondFraction * 1000.0), 999); } else { // HH:mm:ss or HH:mm:ss.zzz - second = string.mid(6, 2).toInt(&ok); + second = C.toInt(string.mid(6, qMin(qsizetype(2), string.size() - 6)), &ok); if (!ok) return QTime(); if (size > 8 && (string.at(8) == QLatin1Char(',') || string.at(8) == QLatin1Char('.'))) { - const QStringRef msecStr(string.mid(9, 4)); - int msecInt = msecStr.isEmpty() ? 0 : msecStr.toInt(&ok); + QStringView msecStr(string.mid(9, qMin(qsizetype(4), string.size() - 9))); + // toInt() ignores leading spaces, so catch them before calling it + if (!msecStr.isEmpty() && !msecStr.at(0).isDigit()) + return QTime(); + // We do, however, want to ignore *trailing* spaces. + msecStr = msecStr.trimmed(); + int msecInt = msecStr.isEmpty() ? 0 : C.toInt(msecStr, &ok); if (!ok) return QTime(); - const double secondFraction(msecInt / (std::pow(double(10), msecStr.count()))); + const double secondFraction(msecInt / (std::pow(double(10), msecStr.size()))); msec = qMin(qRound(secondFraction * 1000.0), 999); } } @@ -2428,7 +2435,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format) case Qt::ISODateWithMs: case Qt::TextDate: default: - return fromIsoTimeString(QStringRef(&string), format, nullptr); + return fromIsoTimeString(QStringView(string), format, nullptr); } } @@ -3410,6 +3417,7 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT DaylightStatus hint, QDate *zoneDate, QTime *zoneTime) { + Q_ASSERT(zone.isValid()); // Get the effective data from QTimeZone QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint)); // Docs state any time before 1970-01-01 will *not* have any DST applied @@ -3799,8 +3807,9 @@ QTimeZone QDateTime::timeZone() const case Qt::OffsetFromUTC: return QTimeZone(d->m_offsetFromUtc); case Qt::TimeZone: - Q_ASSERT(d->m_timeZone.isValid()); - return d->m_timeZone; + if (d->m_timeZone.isValid()) + return d->m_timeZone; + break; case Qt::LocalTime: return QTimeZone::systemTimeZone(); } @@ -3884,6 +3893,7 @@ QString QDateTime::timeZoneAbbreviation() const #if !QT_CONFIG(timezone) break; #else + Q_ASSERT(d->m_timeZone.isValid()); return d->m_timeZone.d->abbreviation(toMSecsSinceEpoch()); #endif // timezone case Qt::LocalTime: { @@ -3920,6 +3930,7 @@ bool QDateTime::isDaylightTime() const #if !QT_CONFIG(timezone) break; #else + Q_ASSERT(d->m_timeZone.isValid()); return d->m_timeZone.d->isDaylightTime(toMSecsSinceEpoch()); #endif // timezone case Qt::LocalTime: { @@ -4044,6 +4055,10 @@ void QDateTime::setTimeZone(const QTimeZone &toZone) */ qint64 QDateTime::toMSecsSinceEpoch() const { + // Note: QDateTimeParser relies on this producing a useful result, even when + // !isValid(), at least when the invalidity is a time in a fall-back (that + // we'll have adjusted to lie outside it, but marked invalid because it's + // not what was asked for). Other things may be doing similar. switch (getSpec(d)) { case Qt::UTC: return getMSecs(d); @@ -4058,12 +4073,13 @@ qint64 QDateTime::toMSecsSinceEpoch() const } case Qt::TimeZone: -#if !QT_CONFIG(timezone) - return 0; -#else - return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone, - extractDaylightStatus(getStatus(d))); +#if QT_CONFIG(timezone) + if (d->m_timeZone.isValid()) { + return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone, + extractDaylightStatus(getStatus(d))); + } #endif + return 0; } Q_UNREACHABLE(); return 0; @@ -4158,9 +4174,11 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs) case Qt::TimeZone: Q_ASSERT(!d.isShort()); #if QT_CONFIG(timezone) + d.detach(); + if (!d->m_timeZone.isValid()) + break; // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied // but all affected times afterwards will have DST applied. - d.detach(); if (msecs >= 0) { status = mergeDaylightStatus(status, d->m_timeZone.d->isDaylightTime(msecs) @@ -4433,7 +4451,7 @@ static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date, QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime; localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time); #if QT_CONFIG(timezone) - } else if (spec == Qt::TimeZone) { + } else if (spec == Qt::TimeZone && d->m_timeZone.isValid()) { QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time), d->m_timeZone, QDateTimePrivate::UnknownDaylightTime, @@ -5094,7 +5112,8 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone { QDateTime dt; dt.setTimeZone(timeZone); - dt.setMSecsSinceEpoch(msecs); + if (timeZone.isValid()) + dt.setMSecsSinceEpoch(msecs); return dt; } @@ -5197,16 +5216,17 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) if (!date.isValid()) return QDateTime(); if (size == 10) - return QDateTime(date); + return date.startOfDay(); Qt::TimeSpec spec = Qt::LocalTime; - QStringRef isoString(&string); - isoString = isoString.mid(10); // trim "yyyy-MM-dd" + QStringView isoString = QStringView(string).mid(10); // trim "yyyy-MM-dd" - // Must be left with T and at least one digit for the hour: + // Must be left with T (or space) and at least one digit for the hour: if (isoString.size() < 2 - || !(isoString.startsWith(QLatin1Char('T')) - // FIXME: QSql relies on QVariant::toDateTime() accepting a space here: + || !(isoString.startsWith(QLatin1Char('T'), Qt::CaseInsensitive) + // RFC 3339 (section 5.6) allows a space here. (It actually + // allows any separator one considers more readable, merely + // giving space as an example - but let's not go wild !) || isoString.startsWith(QLatin1Char(' ')))) { return QDateTime(); } @@ -5214,7 +5234,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) int offset = 0; // Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset - if (isoString.endsWith(QLatin1Char('Z'))) { + if (isoString.endsWith(QLatin1Char('Z'), Qt::CaseInsensitive)) { spec = Qt::UTC; isoString.chop(1); // trim 'Z' } else { @@ -5345,7 +5365,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) if (parts.count() == 5) return QDateTime(date, time, Qt::LocalTime); - QStringRef tz = parts.at(5); + QStringView tz = parts.at(5); if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive)) return QDateTime(); tz = tz.mid(3); diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp index a487534528..fa0884c827 100644 --- a/src/corelib/time/qdatetimeparser.cpp +++ b/src/corelib/time/qdatetimeparser.cpp @@ -1363,7 +1363,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, // given date (which might be a spring-forward, skipping an hour). if (parserType == QVariant::DateTime && !(isSet & HourSectionMask) && !when.isValid()) { qint64 msecs = when.toMSecsSinceEpoch(); - // Fortunately, that gets a useful answer ... + // Fortunately, that gets a useful answer, even though when is invalid ... const QDateTime replace = #if QT_CONFIG(timezone) tspec == Qt::TimeZone diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index 7d6ef0a404..facdf6661d 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -381,18 +381,15 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, On the first pass, the case we consider is what hint told us to expect (except when hint was -1 and didn't actually tell us what to expect), so it's likely right. We only get a second pass if the first failed, - by which time the second case, that we're trying, is likely right. If - an overwhelming majority of calls have hint == -1, the Q_LIKELY here - shall be wrong half the time; otherwise, its errors shall be rarer - than that. + by which time the second case, that we're trying, is likely right. */ if (nextFirst ? i == 0 : i) { Q_ASSERT(nextStart != invalidMSecs()); - if (Q_LIKELY(nextStart <= nextTran.atMSecsSinceEpoch)) + if (nextStart <= nextTran.atMSecsSinceEpoch) return nextTran; } else { // If next is invalid, nextFirst is false, to route us here first: - if (nextStart == invalidMSecs() || Q_LIKELY(nextStart > tran.atMSecsSinceEpoch)) + if (nextStart == invalidMSecs() || nextStart > tran.atMSecsSinceEpoch) return tran; } } @@ -421,7 +418,7 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, int early = offsetFromUtc(recent); int late = offsetFromUtc(imminent); - if (Q_LIKELY(early == late)) { // > 99% of the time + if (early == late) { // > 99% of the time utcEpochMSecs = forLocalMSecs - early * 1000; } else { // Close to a DST transition: early > late is near a fall-back, @@ -433,7 +430,7 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, const qint64 forStd = forLocalMSecs - offsetInStd * 1000; // Best guess at the answer: const qint64 hinted = hint > 0 ? forDst : forStd; - if (Q_LIKELY(offsetFromUtc(hinted) == (hint > 0 ? offsetInDst : offsetInStd))) { + if (offsetFromUtc(hinted) == (hint > 0 ? offsetInDst : offsetInStd)) { utcEpochMSecs = hinted; } else if (hint <= 0 && offsetFromUtc(forDst) == offsetInDst) { utcEpochMSecs = forDst; diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h index b01ce0db58..aa79e0d4a9 100644 --- a/src/corelib/tools/qalgorithms.h +++ b/src/corelib/tools/qalgorithms.h @@ -535,7 +535,7 @@ QT_DEPRECATED_X("Use std::binary_search") Q_OUTOFLINE_TEMPLATE RandomAccessItera # define QT_HAS_BUILTIN_CTZS Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept { -# if QT_HAS_BUILTIN(__builtin_ctzs) +# if __has_builtin(__builtin_ctzs) return __builtin_ctzs(v); # else return __builtin_ctz(v); @@ -544,7 +544,7 @@ Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept #define QT_HAS_BUILTIN_CLZS Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept { -# if QT_HAS_BUILTIN(__builtin_clzs) +# if __has_builtin(__builtin_clzs) return __builtin_clzs(v); # else return __builtin_clz(v) - 16U; diff --git a/src/corelib/tools/qscopeguard.h b/src/corelib/tools/qscopeguard.h index 45c3f93da4..40d2747b1d 100644 --- a/src/corelib/tools/qscopeguard.h +++ b/src/corelib/tools/qscopeguard.h @@ -51,7 +51,7 @@ template QScopeGuard qScopeGuard(F f); template class -#if QT_HAS_CPP_ATTRIBUTE(nodiscard) +#if __has_cpp_attribute(nodiscard) // Q_REQUIRED_RESULT can be defined as __warn_unused_result__ or as [[nodiscard]] // but the 1st one has some limitations for example can be placed only on functions. Q_REQUIRED_RESULT @@ -91,7 +91,7 @@ private: template -#if QT_HAS_CPP_ATTRIBUTE(nodiscard) +#if __has_cpp_attribute(nodiscard) Q_REQUIRED_RESULT #endif QScopeGuard qScopeGuard(F f) diff --git a/src/gui/kernel/qplatformcursor.cpp b/src/gui/kernel/qplatformcursor.cpp index 12065078c1..5a438a54a2 100644 --- a/src/gui/kernel/qplatformcursor.cpp +++ b/src/gui/kernel/qplatformcursor.cpp @@ -131,6 +131,14 @@ void QPlatformCursor::setPos(const QPoint &pos) QWindowSystemInterface::handleMouseEvent(nullptr, pos, pos, Qt::NoButton, Qt::NoButton, QEvent::MouseMove); } +/*! + Returns the size of the cursor, in native pixels. +*/ +QSize QPlatformCursor::size() const +{ + return QSize(16, 16); +} + // End of display and pointer event handling code // Beginning of built-in cursor graphics // from src/gui/embedded/QGraphicsSystemCursorImage_qws.cpp diff --git a/src/gui/kernel/qplatformcursor.h b/src/gui/kernel/qplatformcursor.h index f36a73c861..f3871d8780 100644 --- a/src/gui/kernel/qplatformcursor.h +++ b/src/gui/kernel/qplatformcursor.h @@ -96,6 +96,7 @@ public: #endif // QT_NO_CURSOR virtual QPoint pos() const; virtual void setPos(const QPoint &pos); + virtual QSize size() const; static Capabilities capabilities() { return m_capabilities; } static void setCapabilities(Capabilities c) { m_capabilities = c; } diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp index 937bb505c9..9631fdb416 100644 --- a/src/gui/painting/qcolorspace.cpp +++ b/src/gui/painting/qcolorspace.cpp @@ -784,10 +784,12 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace) QDebugStateSaver saver(dbg); dbg.nospace(); dbg << "QColorSpace("; - if (colorSpace.d_ptr->namedColorSpace) - dbg << colorSpace.d_ptr->namedColorSpace << ", "; - dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction(); - dbg << ", gamma=" << colorSpace.gamma(); + if (colorSpace.d_ptr) { + if (colorSpace.d_ptr->namedColorSpace) + dbg << colorSpace.d_ptr->namedColorSpace << ", "; + dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction(); + dbg << ", gamma=" << colorSpace.gamma(); + } dbg << ')'; return dbg; } diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 563d59b318..3fb2ec38a7 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -2428,7 +2428,15 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC f->glUniformMatrix2fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast(src)); break; case QShaderDescription::Mat3: - f->glUniformMatrix3fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast(src)); + { + // 4 floats per column (or row, if row-major) + float mat[9]; + const float *srcMat = reinterpret_cast(src); + memcpy(mat, srcMat, 3 * sizeof(float)); + memcpy(mat + 3, srcMat + 4, 3 * sizeof(float)); + memcpy(mat + 6, srcMat + 8, 3 * sizeof(float)); + f->glUniformMatrix3fv(uniform.glslLocation, 1, GL_FALSE, mat); + } break; case QShaderDescription::Mat4: f->glUniformMatrix4fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast(src)); @@ -2919,21 +2927,64 @@ bool QRhiGles2::linkProgram(GLuint program) return true; } -void QRhiGles2::gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub, +void QRhiGles2::registerUniformIfActive(const QShaderDescription::BlockVariable &var, + const QByteArray &namePrefix, + int binding, + int baseOffset, + GLuint program, + QVector *dst) +{ + if (var.type == QShaderDescription::Struct) { + qWarning("Nested structs are not supported at the moment. '%s' ignored.", + qPrintable(var.name)); + return; + } + QGles2UniformDescription uniform; + uniform.type = var.type; + const QByteArray name = namePrefix + var.name.toUtf8(); + uniform.glslLocation = f->glGetUniformLocation(program, name.constData()); + if (uniform.glslLocation >= 0) { + uniform.binding = binding; + uniform.offset = uint(baseOffset + var.offset); + uniform.size = var.size; + dst->append(uniform); + } +} + +void QRhiGles2::gatherUniforms(GLuint program, + const QShaderDescription::UniformBlock &ub, QVector *dst) { - const QByteArray prefix = ub.structName.toUtf8() + '.'; + QByteArray prefix = ub.structName.toUtf8() + '.'; for (const QShaderDescription::BlockVariable &blockMember : ub.members) { - // ### no array support for now - QGles2UniformDescription uniform; - uniform.type = blockMember.type; - const QByteArray name = prefix + blockMember.name.toUtf8(); - uniform.glslLocation = f->glGetUniformLocation(program, name.constData()); - if (uniform.glslLocation >= 0) { - uniform.binding = ub.binding; - uniform.offset = uint(blockMember.offset); - uniform.size = blockMember.size; - dst->append(uniform); + if (blockMember.type == QShaderDescription::Struct) { + prefix += blockMember.name.toUtf8(); + const int baseOffset = blockMember.offset; + if (blockMember.arrayDims.isEmpty()) { + for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers) + registerUniformIfActive(structMember, prefix, ub.binding, baseOffset, program, dst); + } else { + if (blockMember.arrayDims.count() > 1) { + qWarning("Array of struct '%s' has more than one dimension. Only the first dimension is used.", + qPrintable(blockMember.name)); + } + const int dim = blockMember.arrayDims.first(); + const int elemSize = blockMember.size / dim; + int elemOffset = baseOffset; + for (int di = 0; di < dim; ++di) { + const QByteArray arrayPrefix = prefix + '[' + QByteArray::number(di) + ']' + '.'; + for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers) + registerUniformIfActive(structMember, arrayPrefix, ub.binding, elemOffset, program, dst); + elemOffset += elemSize; + } + } + } else { + if (!blockMember.arrayDims.isEmpty()) { + qWarning("Arrays are only supported for structs at the moment. '%s' ignored.", + qPrintable(blockMember.name)); + continue; + } + registerUniformIfActive(blockMember, prefix, ub.binding, 0, program, dst); } } } diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index 0283fadb4e..4a98011d3d 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -706,7 +706,14 @@ public: QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion); bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion); bool linkProgram(GLuint program); - void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub, + void registerUniformIfActive(const QShaderDescription::BlockVariable &var, + const QByteArray &namePrefix, + int binding, + int baseOffset, + GLuint program, + QVector *dst); + void gatherUniforms(GLuint program, + const QShaderDescription::UniformBlock &ub, QVector *dst); void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v, QVector *dst); diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 555ed5e79f..3aa68db585 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -3215,7 +3215,10 @@ id QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var [opts release]; // src is autoreleased - if (err) { + // if lib is null and err is non-null, we had errors (fail) + // if lib is non-null and err is non-null, we had warnings (success) + // if lib is non-null and err is null, there were no errors or warnings (success) + if (!lib) { const QString msg = QString::fromNSString(err.localizedDescription); *error = msg; return nil; diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index b69b94d4e7..fa323ef4bd 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -2261,6 +2261,7 @@ void QTextCursor::insertFragment(const QTextDocumentFragment &fragment) d->remove(); fragment.d->insert(*this); d->priv->endEditBlock(); + d->setX(); if (fragment.d && fragment.d->doc) d->priv->mergeCachedResources(fragment.d->doc->docHandle()); diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 3382ec0b69..1d27cc30eb 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -347,7 +347,19 @@ QTextDocument *QTextDocument::clone(QObject *parent) const { Q_D(const QTextDocument); QTextDocument *doc = new QTextDocument(parent); - QTextCursor(doc).insertFragment(QTextDocumentFragment(this)); + if (isEmpty()) { + const QTextCursor thisCursor(const_cast(this)); + + const auto blockFormat = thisCursor.blockFormat(); + if (blockFormat.isValid() && !blockFormat.isEmpty()) + QTextCursor(doc).setBlockFormat(blockFormat); + + const auto blockCharFormat = thisCursor.blockCharFormat(); + if (blockCharFormat.isValid() && !blockCharFormat.isEmpty()) + QTextCursor(doc).setBlockCharFormat(blockCharFormat); + } else { + QTextCursor(doc).insertFragment(QTextDocumentFragment(this)); + } doc->rootFrame()->setFrameFormat(rootFrame()->frameFormat()); QTextDocumentPrivate *priv = doc->d_func(); priv->title = d->title; diff --git a/src/plugins/platforms/cocoa/qcocoaclipboard.mm b/src/plugins/platforms/cocoa/qcocoaclipboard.mm index a35c153084..141940cc50 100644 --- a/src/plugins/platforms/cocoa/qcocoaclipboard.mm +++ b/src/plugins/platforms/cocoa/qcocoaclipboard.mm @@ -67,7 +67,7 @@ void QCocoaClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) } pasteBoard->sync(); - pasteBoard->setMimeData(data); + pasteBoard->setMimeData(data, QMacPasteboard::LazyRequest); emitChanged(mode); } } diff --git a/src/plugins/platforms/cocoa/qcocoacursor.h b/src/plugins/platforms/cocoa/qcocoacursor.h index 58b9ef2151..5b008eff35 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.h +++ b/src/plugins/platforms/cocoa/qcocoacursor.h @@ -56,6 +56,9 @@ public: void changeCursor(QCursor *cursor, QWindow *window) override; QPoint pos() const override; void setPos(const QPoint &position) override; + + QSize size() const override; + private: QHash m_cursors; NSCursor *convertCursor(QCursor *cursor); diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index 87a57c78c8..e0d623fc4c 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -85,6 +85,31 @@ void QCocoaCursor::setPos(const QPoint &position) CFRelease(e); } + +QSize QCocoaCursor::size() const +{ + NSCursor *cocoaCursor = NSCursor.currentSystemCursor; + if (!cocoaCursor) + return QPlatformCursor::size(); + NSImage *cursorImage = cocoaCursor.image; + if (!cursorImage) + return QPlatformCursor::size(); + + QSizeF size = QSizeF::fromCGSize(cursorImage.size); + NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults; + NSDictionary *accessSettings = [defaults persistentDomainForName:@"com.apple.universalaccess"]; + if (accessSettings == nil) + return size.toSize(); + + float sizeScale = [accessSettings[@"mouseDriverCursorSize"] floatValue]; + if (sizeScale > 0) { + size.rwidth() *= sizeScale; + size.rheight() *= sizeScale; + } + + return size.toSize(); +} + NSCursor *QCocoaCursor::convertCursor(QCursor *cursor) { if (!cursor) diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 69587a24be..b8d2532b8e 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -186,6 +186,7 @@ public: QAtomicInt serialNumber; int lastSerial; bool interrupt; + bool propagateInterrupt = false; static void postedEventsSourceCallback(void *info); static void waitingObserverCallback(CFRunLoopObserverRef observer, diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 110c82bf1f..94b9e62eab 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -84,13 +84,12 @@ #include "private/qthread_p.h" #include "private/qguiapplication_p.h" #include +#include #include QT_BEGIN_NAMESPACE -QT_USE_NAMESPACE - static inline CFRunLoopRef mainRunLoop() { return CFRunLoopGetMain(); @@ -348,6 +347,16 @@ static inline void qt_mac_waitForMoreEvents(NSString *runLoopMode = NSDefaultRun bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QCocoaEventDispatcher); + + // In rare rather corner cases a user's application messes with + // QEventLoop::exec()/exit() and QCoreApplication::processEvents(), + // we have to undo what bool blocker normally does. + d->propagateInterrupt = false; + const auto boolBlockerUndo = qScopeGuard([d](){ + if (d->propagateInterrupt) + d->interrupt = true; + d->propagateInterrupt = false; + }); QBoolBlocker interruptBlocker(d->interrupt, false); bool interruptLater = false; @@ -496,7 +505,16 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) { // When called "manually", always process posted events and timers + bool oldInterrupt = d->interrupt; d->processPostedEvents(); + if (!oldInterrupt && d->interrupt && !d->currentModalSession()) { + // We had direct processEvent call, coming not from QEventLoop::exec(). + // One of the posted events triggered an application to interrupt the loop. + // But bool blocker will reset d->interrupt to false, so the real event + // loop will never notice it was interrupted. Now we'll have to fix it by + // enforcing the value of d->interrupt. + d->propagateInterrupt = true; + } retVal = d->processTimers() || retVal; } diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 4210a4ed3f..238067568b 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -86,6 +86,10 @@ private: QSurfaceFormat m_format; QVarLengthArray m_updateObservers; QAtomicInt m_needsUpdate = false; + +#ifndef QT_NO_DEBUG_STREAM + friend QDebug operator<<(QDebug debug, const QCocoaGLContext *screen); +#endif }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index b312e033cd..6db4bdb9fd 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -158,6 +158,8 @@ void QCocoaGLContext::initialize() [m_context setValues:&order forParameter:NSOpenGLCPSurfaceOrder]; updateSurfaceFormat(); + + qCDebug(lcQpaOpenGLContext).verbosity(3) << "Created" << this << "based on requested" << context()->format(); } NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurfaceFormat &format) @@ -355,7 +357,7 @@ QCocoaGLContext::~QCocoaGLContext() bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) { - qCDebug(lcQpaOpenGLContext) << "Making" << m_context << "current" + qCDebug(lcQpaOpenGLContext) << "Making" << this << "current" << "in" << QThread::currentThread() << "for" << surface; Q_ASSERT(surface->surface()->supportsOpenGL()); @@ -555,4 +557,20 @@ QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName) return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName); } +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QCocoaGLContext *context) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug << "QCocoaGLContext(" << (const void *)context; + if (context) { + if (debug.verbosity() > QDebug::DefaultVerbosity) + debug << ", " << context->format(); + debug << ", " << context->nativeContext(); + } + debug << ')'; + return debug; +} +#endif // !QT_NO_DEBUG_STREAM + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 643eac1e92..ad232d6d80 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -559,7 +559,10 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) { NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior; - if ((flags & Qt::WindowFullscreenButtonHint) || m_view.window.qt_fullScreen) { + const bool enableFullScreen = m_view.window.qt_fullScreen + || !(flags & Qt::CustomizeWindowHint) + || (flags & Qt::WindowFullscreenButtonHint); + if (enableFullScreen) { behavior |= NSWindowCollectionBehaviorFullScreenPrimary; behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary; } else { diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index 358a6b49fd..654647b35a 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -138,8 +138,12 @@ QMacPasteboard::QMacPasteboard(CFStringRef name, uchar mt) QMacPasteboard::~QMacPasteboard() { - // commit all promises for paste after exit close - resolvingBeforeDestruction = true; + /* + Commit all promises for paste when shutting down, + unless we are the stack-allocated clipboard used by QCocoaDrag. + */ + if (mime_type == QMacInternalPasteboardMime::MIME_DND) + resolvingBeforeDestruction = true; PasteboardResolvePromises(paste); if (paste) CFRelease(paste); diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp index 1b5f3b4954..491c314488 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp @@ -60,6 +60,18 @@ static const int c_screenCode = _PULSE_CODE_MINAVAIL + 0; static const int c_armCode = _PULSE_CODE_MINAVAIL + 1; static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2; +#if !defined(screen_register_event) +int screen_register_event(screen_context_t, struct sigevent *event) +{ + return MsgRegisterEvent(event, -1); +} + +int screen_unregister_event(struct sigevent *event) +{ + return MsgUnregisterEvent(event); +} +#endif + QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context) : QThread() , m_screenContext(context) @@ -75,10 +87,14 @@ QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context) qFatal("QQnxScreenEventThread: Can't continue without a channel connection"); } - struct sigevent screenEvent; - SIGEV_PULSE_INIT(&screenEvent, m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_screenCode, 0); + SIGEV_PULSE_INIT(&m_screenEvent, m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_screenCode, 0); + if (screen_register_event(m_screenContext, &m_screenEvent) == -1) { + ConnectDetach(m_connectionId); + ChannelDestroy(m_channelId); + qFatal("QQnxScreenEventThread: Can't continue without a registered event"); + } - screen_notify(m_screenContext, SCREEN_NOTIFY_EVENT, nullptr, &screenEvent); + screen_notify(m_screenContext, SCREEN_NOTIFY_EVENT, nullptr, &m_screenEvent); } QQnxScreenEventThread::~QQnxScreenEventThread() @@ -86,6 +102,8 @@ QQnxScreenEventThread::~QQnxScreenEventThread() // block until thread terminates shutdown(); + screen_notify(m_screenContext, SCREEN_NOTIFY_EVENT, nullptr, nullptr); + screen_unregister_event(&m_screenEvent); ConnectDetach(m_connectionId); ChannelDestroy(m_channelId); } diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.h b/src/plugins/platforms/qnx/qqnxscreeneventthread.h index 3c8d197545..e5b762369c 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventthread.h +++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.h @@ -45,6 +45,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -73,6 +74,7 @@ private: int m_channelId; int m_connectionId; + struct sigevent m_screenEvent; screen_context_t m_screenContext; bool m_emitNeededOnNextScreenPulse = true; int m_screenPulsesSinceLastArmPulse = 0; diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index 37f1ea832a..b6c9b9e377 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -54,6 +54,8 @@ QWasmScreen::QWasmScreen(const QString &canvasId) m_compositor = new QWasmCompositor(this); m_eventTranslator = new QWasmEventTranslator(this); updateQScreenAndCanvasRenderSize(); + emscripten::val canvas = emscripten::val::global(m_canvasId.toUtf8().constData()); + canvas.call("focus"); } QWasmScreen::~QWasmScreen() diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 17e8cffb76..59457f1720 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -50,6 +50,7 @@ #include #include // getPixmapCursor() #include +#include #include #include @@ -686,6 +687,30 @@ void QWindowsCursor::setPos(const QPoint &pos) SetCursorPos(pos.x() , pos.y()); } +/* + The standard size is 32x32, even though the cursor is actually just + 16 pixels large. If a large cursor is set in the accessibility settings, + then the cursor increases with 8 pixels for each step. +*/ +QSize QWindowsCursor::size() const +{ + const QPair cursorSizeSetting = + QWinRegistryKey(HKEY_CURRENT_USER, LR"(Control Panel\Cursors)") + .dwordValue(L"CursorBaseSize"); + const int baseSize = screenCursorSize(m_screen).width() / 2; + if (!cursorSizeSetting.second) + return QSize(baseSize / 2, baseSize / 2); + + // The registry values are dpi-independent, so we need to scale the result. + int cursorSizeValue = cursorSizeSetting.first * m_screen->logicalDpi().first + / m_screen->logicalBaseDpi().first; + + // map from registry value 32-256 to 0-14, and from there to pixels + cursorSizeValue = (cursorSizeValue - 2 * baseSize) / baseSize; + const int cursorSize = baseSize + cursorSizeValue * (baseSize / 2); + return QSize(cursorSize, cursorSize); +} + QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const { switch (action) { diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index b896f4c7a9..cf3635bd6b 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -113,6 +113,8 @@ public: QPoint pos() const override; void setPos(const QPoint &pos) override; + QSize size() const override; + static HCURSOR createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor = 1); static HCURSOR createPixmapCursor(const PixmapCursor &pc, qreal scaleFactor = 1) { return createPixmapCursor(pc.pixmap, pc.hotSpot, scaleFactor); } static PixmapCursor customCursor(Qt::CursorShape cursorShape, const QPlatformScreen *screen = nullptr); diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index f2dba4d06b..ab830e1461 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -57,11 +57,13 @@ #include "qwindowsmenu.h" #include "qwindowsscreen.h" +#include #include #include #include #include #include +#include #include #include @@ -134,9 +136,12 @@ static int indexOfHwnd(HWND hwnd) extern "C" LRESULT QT_WIN_CALLBACK qWindowsTrayIconWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + // QTBUG-79248: Trigger screen update if there are no other windows. + if (message == WM_DPICHANGED && QGuiApplication::topLevelWindows().isEmpty()) + QWindowsContext::instance()->screenManager().handleScreenChanges(); if (message == MYWM_TASKBARCREATED || message == MYWM_NOTIFYICON || message == WM_INITMENU || message == WM_INITMENUPOPUP - || message == WM_COMMAND) { + || message == WM_CLOSE || message == WM_COMMAND) { const int index = indexOfHwnd(hwnd); if (index >= 0) { MSG msg; @@ -439,6 +444,9 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result) case WM_INITMENUPOPUP: QWindowsPopupMenu::notifyAboutToShow(reinterpret_cast(message.wParam)); break; + case WM_CLOSE: + QWindowSystemInterface::handleApplicationTermination(); + break; case WM_COMMAND: QWindowsPopupMenu::notifyTriggered(LOWORD(message.wParam)); break; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index e5a9f275ae..cc293b777c 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -289,7 +289,8 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow break; case UIA_TogglePatternId: // Checkbox controls. - if (accessible->role() == QAccessible::CheckBox) { + if (accessible->role() == QAccessible::CheckBox + || (accessible->role() == QAccessible::MenuItem && accessible->state().checkable)) { *pRetVal = new QWindowsUiaToggleProvider(id()); } break; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 8bcaa78122..cc84e836b4 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -41,6 +41,7 @@ #include "qxcbwindow.h" #include "qxcbcursor.h" #include "qxcbimage.h" +#include "qxcbintegration.h" #include "qnamespace.h" #include "qxcbxsettings.h" @@ -49,6 +50,7 @@ #include #include +#include #include #include #include @@ -356,6 +358,15 @@ static QFontEngine::SubpixelAntialiasingType parseXftRgba(const QByteArray& stri void QXcbVirtualDesktop::readXResources() { + const QPlatformServices *services = QXcbIntegration::instance()->services(); + bool useXftConf = false; + if (services) { + const QList desktopEnv = services->desktopEnvironment().split(':'); + useXftConf = desktopEnv.contains("GNOME") || desktopEnv.contains("UNITY") || desktopEnv.contains("XFCE"); + } + if (!useXftConf) + return; + int offset = 0; QByteArray resources; while (true) { diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index 68313b7ff0..3d8ed29b54 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -838,6 +838,7 @@ QSqlRecord QPSQLResult::record() const } int ptype = PQftype(d->result, i); f.setType(qDecodePSQLType(ptype)); + f.setValue(QVariant(f.type())); // only set in setType() when it's invalid before int len = PQfsize(d->result, i); int precision = PQfmod(d->result, i); diff --git a/src/testlib/doc/snippets/code/doc_src_cmakelists.txt b/src/testlib/doc/snippets/code/doc_src_cmakelists.txt new file mode 100644 index 0000000000..96dbe1acee --- /dev/null +++ b/src/testlib/doc/snippets/code/doc_src_cmakelists.txt @@ -0,0 +1,14 @@ +project(mytest LANGUAGES CXX) + +find_package(Qt5Test REQUIRED) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) + +enable_testing(true) + +add_executable(mytest tst_mytest.cpp) +add_test(NAME mytest COMMAND mytest) + +target_link_libraries(mytest PRIVATE Qt5::Test) diff --git a/src/testlib/doc/src/qttestlib-manual.qdoc b/src/testlib/doc/src/qttestlib-manual.qdoc index 19d871d404..688cc2f2f6 100644 --- a/src/testlib/doc/src/qttestlib-manual.qdoc +++ b/src/testlib/doc/src/qttestlib-manual.qdoc @@ -83,6 +83,10 @@ \li Custom types can easily be added to the test data and test output. \endtable + You can use a Qt Creator wizard to create a project that contains Qt tests + and build and run them directly from Qt Creator. For more information, see + \l {Running Autotests}. + \section1 Creating a Test To create a test, subclass QObject and add one or more private slots to it. Each @@ -133,6 +137,41 @@ \if !defined(qtforpython) \section1 Building a Test + You can build an executable that contains one test class that typically + tests one class of production code. However, usually you would want to + test several classes in a project by running one command. + + See \l {Chapter 1: Writing a Unit Test}{Writing a Unit Test} for a step by + step explanation. + + \section2 Building with CMake and CTest + + You can use \l {CMake and CTest} to create a test. + \l{https://cmake.org/cmake/help/latest/manual/ctest.1.html}{CTest} enables + you to include or exclude tests based on a regular expression that is + matched against the test name. You can further apply the \c LABELS property + to a test and CTest can then include or exclude tests based on those labels. + All labeled targets will be run when \c {test} target is called on the + command line. + + There are several other advantages with CMake. For example, the result of + a test run can be published on a web server using CDash with virtually no + effort. + + CTest scales to very different unit test frameworks, and works out of the + box with QTest. + + The following is an example of a CMakeLists.txt file that specifies the + project name and the language used (here, \e mytest and C++), the Qt + modules required for building the test (Qt5Test), and the files that are + included in the test (\e tst_mytest.cpp). + + \quotefile code/doc_src_cmakelists.txt + + For more information about the options you have, see \l {Build with CMake}. + + \section2 Building with qmake + If you are using \c qmake as your build tool, just add the following to your project file: @@ -146,14 +185,14 @@ See the \l{Building a Testcase}{qmake manual} for more information about \c{make check}. + \section2 Building with Other Tools + If you are using other build tools, make sure that you add the location of the Qt Test header files to your include path (usually \c{include/QtTest} under your Qt installation directory). If you are using a release build of Qt, link your test to the \c QtTest library. For debug builds, use \c{QtTest_debug}. - See \l {Chapter 1: Writing a Unit Test}{Writing a Unit Test} for a step by - step explanation. \endif \section1 Qt Test Command Line Arguments diff --git a/src/widgets/accessible/qaccessiblemenu.cpp b/src/widgets/accessible/qaccessiblemenu.cpp index 51ba0adaa6..99a9444ff1 100644 --- a/src/widgets/accessible/qaccessiblemenu.cpp +++ b/src/widgets/accessible/qaccessiblemenu.cpp @@ -299,6 +299,8 @@ QAccessible::State QAccessibleMenuItem::state() const s.disabled = true; if (m_action->isChecked()) s.checked = true; + if (m_action->isCheckable()) + s.checkable = true; return s; } diff --git a/src/widgets/dialogs/qprogressdialog.cpp b/src/widgets/dialogs/qprogressdialog.cpp index 42a24239a3..aaa4430c39 100644 --- a/src/widgets/dialogs/qprogressdialog.cpp +++ b/src/widgets/dialogs/qprogressdialog.cpp @@ -710,14 +710,17 @@ void QProgressDialog::setValue(int progress) QSize QProgressDialog::sizeHint() const { Q_D(const QProgressDialog); - QSize sh = d->label ? d->label->sizeHint() : QSize(0, 0); - QSize bh = d->bar->sizeHint(); - int margin = style()->pixelMetric(QStyle::PM_DefaultTopLevelMargin); - int spacing = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); - int h = margin * 2 + bh.height() + sh.height() + spacing; + QSize labelSize = d->label ? d->label->sizeHint() : QSize(0, 0); + QSize barSize = d->bar->sizeHint(); + int marginBottom = style()->pixelMetric(QStyle::PM_LayoutBottomMargin, 0, this); + int spacing = style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing, 0, this); + int marginLeft = style()->pixelMetric(QStyle::PM_LayoutLeftMargin, 0, this); + int marginRight = style()->pixelMetric(QStyle::PM_LayoutRightMargin, 0, this); + + int height = marginBottom * 2 + barSize.height() + labelSize.height() + spacing; if (d->cancel) - h += d->cancel->sizeHint().height() + spacing; - return QSize(qMax(200, sh.width() + 2 * margin), h); + height += d->cancel->sizeHint().height() + spacing; + return QSize(qMax(200, labelSize.width() + marginLeft + marginRight), height); } /*!\reimp diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 67c01adea7..0e54cf235f 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -3074,9 +3074,10 @@ void QAbstractItemView::keyboardSearch(const QString &search) QSize QAbstractItemView::sizeHintForIndex(const QModelIndex &index) const { Q_D(const QAbstractItemView); - if (!d->isIndexValid(index) || !d->itemDelegate) + if (!d->isIndexValid(index)) return QSize(); - return d->delegateForIndex(index)->sizeHint(d->viewOptionsV1(), index); + const auto delegate = d->delegateForIndex(index); + return delegate ? delegate->sizeHint(d->viewOptionsV1(), index) : QSize(); } /*! @@ -3318,6 +3319,8 @@ void QAbstractItemView::update(const QModelIndex &index) The \a roles which have been changed can either be an empty container (meaning everything has changed), or a non-empty container with the subset of roles which have changed. + + \note: Qt::ToolTipRole is not honored by dataChanged() in the views provided by Qt. */ void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { @@ -4451,7 +4454,9 @@ QItemViewPaintPairs QAbstractItemViewPrivate::draggablePaintPairs(const QModelIn rect |= current; } } - rect &= viewportRect; + QRect clipped = rect & viewportRect; + rect.setLeft(clipped.left()); + rect.setRight(clipped.right()); return ret; } diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index de32082b5a..ec01922746 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -664,7 +664,9 @@ QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(const QModelIndexList rect |= current; } } - rect &= viewportRect; + QRect clipped = rect & viewportRect; + rect.setLeft(clipped.left()); + rect.setRight(clipped.right()); return ret; } diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index b290713440..33dd3e59b6 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -53,11 +53,14 @@ #endif #include #include +#include +#include #include #ifndef QT_NO_TOOLTIP #include #include +#include #include QT_BEGIN_NAMESPACE @@ -398,24 +401,34 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w) } #endif //QT_NO_STYLE_STYLESHEET - - QRect screen = QDesktopWidgetPrivate::screenGeometry(getTipScreen(pos, w)); - QPoint p = pos; - p += QPoint(2, 16); + int screenNumber = getTipScreen(pos, w); + QScreen *screen = QGuiApplication::screens().at(screenNumber); + if (screen) { + const QPlatformScreen *platformScreen = screen->handle(); + const QSize cursorSize = QHighDpi::fromNativePixels(platformScreen->cursor()->size(), + platformScreen); + QPoint offset(2, cursorSize.height()); + // assuming an arrow shape, we can just move to the side for very large cursors + if (cursorSize.height() > 2 * this->height()) + offset = QPoint(cursorSize.width() / 2, 0); - if (p.x() + this->width() > screen.x() + screen.width()) + p += offset; + + QRect screenRect = screen->geometry(); + if (p.x() + this->width() > screenRect.x() + screenRect.width()) p.rx() -= 4 + this->width(); - if (p.y() + this->height() > screen.y() + screen.height()) + if (p.y() + this->height() > screenRect.y() + screenRect.height()) p.ry() -= 24 + this->height(); - if (p.y() < screen.y()) - p.setY(screen.y()); - if (p.x() + this->width() > screen.x() + screen.width()) - p.setX(screen.x() + screen.width() - this->width()); - if (p.x() < screen.x()) - p.setX(screen.x()); - if (p.y() + this->height() > screen.y() + screen.height()) - p.setY(screen.y() + screen.height() - this->height()); + if (p.y() < screenRect.y()) + p.setY(screenRect.y()); + if (p.x() + this->width() > screenRect.x() + screenRect.width()) + p.setX(screenRect.x() + screenRect.width() - this->width()); + if (p.x() < screenRect.x()) + p.setX(screenRect.x()); + if (p.y() + this->height() > screenRect.y() + screenRect.height()) + p.setY(screenRect.y() + screenRect.height() - this->height()); + } this->move(p); } diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index f507745e1e..ecea94c66a 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -8621,6 +8621,23 @@ bool QWidget::event(QEvent *event) } } switch (event->type()) { + case QEvent::PlatformSurface: { + // Sync up QWidget's view of whether or not the widget has been created + switch (static_cast(event)->surfaceEventType()) { + case QPlatformSurfaceEvent::SurfaceCreated: + if (!testAttribute(Qt::WA_WState_Created)) + create(); + break; + case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: + if (testAttribute(Qt::WA_WState_Created)) { + // Child windows have already been destroyed by QWindow, + // so we skip them here. + destroy(false, false); + } + break; + } + break; + } case QEvent::MouseMove: mouseMoveEvent((QMouseEvent*)event); break; diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 6b3e3679ae..03081658bb 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -1363,7 +1363,6 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, if (!button->icon.isNull()) { //Center both icon and text - QRect iconRect; QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && button->state & State_HasFocus) mode = QIcon::Active; @@ -1372,28 +1371,29 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, state = QIcon::On; QPixmap pixmap = button->icon.pixmap(qt_getWindow(widget), button->iconSize, mode, state); - int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio(); int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio(); int labelWidth = pixmapWidth; int labelHeight = pixmapHeight; int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint() - int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width(); - if (!button->text.isEmpty()) + if (!button->text.isEmpty()) { + int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width(); labelWidth += (textWidth + iconSpacing); + } - iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2, - textRect.y() + (textRect.height() - labelHeight) / 2, - pixmapWidth, pixmapHeight); + QRect iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2, + textRect.y() + (textRect.height() - labelHeight) / 2, + pixmapWidth, pixmapHeight); iconRect = visualRect(button->direction, textRect, iconRect); - tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead - - if (button->direction == Qt::RightToLeft) + if (button->direction == Qt::RightToLeft) { + tf |= Qt::AlignRight; textRect.setRight(iconRect.left() - iconSpacing); - else + } else { + tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing); + } if (button->state & (State_On | State_Sunken)) iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget), diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index a732d59e48..0c668913e9 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -1770,59 +1770,10 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio break; case CE_PushButtonLabel: if (const QStyleOptionButton *button = qstyleoption_cast(option)) { - QRect ir = button->rect; - uint tf = Qt::AlignVCenter; - if (styleHint(SH_UnderlineShortcut, button, widget)) - tf |= Qt::TextShowMnemonic; - else - tf |= Qt::TextHideMnemonic; - - if (!button->icon.isNull()) { - //Center both icon and text - QPoint point; - - QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal - : QIcon::Disabled; - if (mode == QIcon::Normal && button->state & State_HasFocus) - mode = QIcon::Active; - QIcon::State state = QIcon::Off; - if (button->state & State_On) - state = QIcon::On; - - QPixmap pixmap = button->icon.pixmap(qt_getWindow(widget), button->iconSize, mode, state); - int w = pixmap.width() / pixmap.devicePixelRatio(); - int h = pixmap.height() / pixmap.devicePixelRatio(); - - if (!button->text.isEmpty()) - w += button->fontMetrics.boundingRect(option->rect, tf, button->text).width() + 2; - - point = QPoint(ir.x() + ir.width() / 2 - w / 2, - ir.y() + ir.height() / 2 - h / 2); - - w = pixmap.width() / pixmap.devicePixelRatio(); - - if (button->direction == Qt::RightToLeft) - point.rx() += w; - - painter->drawPixmap(visualPos(button->direction, button->rect, point), pixmap); - - if (button->direction == Qt::RightToLeft) - ir.translate(-point.x() - 2, 0); - else - ir.translate(point.x() + w, 0); - - // left-align text if there is - if (!button->text.isEmpty()) - tf |= Qt::AlignLeft; - - } else { - tf |= Qt::AlignHCenter; - } - - if (button->features & QStyleOptionButton::HasMenu) - ir = ir.adjusted(0, 0, -proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget), 0); - proxy()->drawItemText(painter, ir, tf, button->palette, (button->state & State_Enabled), - button->text, QPalette::ButtonText); + QStyleOptionButton b(*button); + // no PM_ButtonShiftHorizontal and PM_ButtonShiftVertical for fusion style + b.state &= ~(State_On | State_Sunken); + QCommonStyle::drawControl(element, &b, painter, widget); } break; case CE_MenuBarEmptyArea: diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index c40bbbc96c..7e8c9a6050 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -3501,6 +3501,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q } else { QWindowsStyle::drawControl(ce, &btnOpt, p, w); } + rule.drawImage(p, rule.contentsRect(opt->rect)); if (!customMenu) return; } else { @@ -3730,6 +3731,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q bool dis = !(opt->state & QStyle::State_Enabled), act = opt->state & QStyle::State_Selected; + int textRectOffset = m->maxIconWidth; if (!mi.icon.isNull()) { QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; if (act && !dis) @@ -3755,19 +3757,21 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q p->drawPixmap(pmr.topLeft(), pixmap); } else if (checkable) { QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark); + const QRect cmRect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction); if (subSubRule.hasDrawable() || checked) { QStyleOptionMenuItem newMi = mi; if (!dis) newMi.state |= State_Enabled; - if (act) + if (mi.checked) newMi.state |= State_On; - newMi.rect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction); + newMi.rect = cmRect; drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w); } + textRectOffset = std::max(textRectOffset, cmRect.width()); } QRect textRect = subRule.contentsRect(opt->rect); - textRect.setLeft(textRect.left() + m->maxIconWidth); + textRect.setLeft(textRect.left() + textRectOffset); textRect.setWidth(textRect.width() - mi.tabWidth); const QRect vTextRect = visualRect(opt->direction, m->rect, textRect); diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp index b0689d0b9e..3d6716666d 100644 --- a/src/widgets/widgets/qdatetimeedit.cpp +++ b/src/widgets/widgets/qdatetimeedit.cpp @@ -90,12 +90,10 @@ QT_BEGIN_NAMESPACE today's date, and restricted the valid date range to today plus or minus 365 days. We've set the order to month, day, year. - The minimum value for QDateTimeEdit is 14 September 1752. You can - change this by calling setMinimumDate(), taking into account that - the minimum value for QDate is 2 January 4713BC. - - Other useful functions are setMaximumDate(), setMinimumTime() - and setMaximumTime(). + The range of valid values for a QDateTimeEdit is controlled by the properties + \l minimumDateTime, \l maximumDateTime, and their respective date and time + components. By default, any date-time from the start of 100 CE to the end of + 9999 CE is valid. \section1 Using a Pop-up Calendar Widget @@ -223,10 +221,16 @@ QDateTimeEdit::~QDateTimeEdit() When setting this property the timespec of the QDateTimeEdit remains the same and the timespec of the new QDateTime is ignored. - By default, this property contains a date that refers to January 1, - 2000 and a time of 00:00:00 and 0 milliseconds. + By default, this property is set to the start of 2000 CE. It can only be set + to a valid QDateTime value. If any operation causes this property to have an + invalid date-time as value, it is reset to the value of the \l minimumDateTime + property. - \sa date, time + If the QDateTimeEdit has no date fields, setting this property sets the + widget's date-range to start and end on the date of the new value of this + property. + + \sa date, time, minimumDateTime, maximumDateTime */ QDateTime QDateTimeEdit::dateTime() const @@ -329,25 +333,23 @@ void QDateTimeEdit::setCalendar(QCalendar calendar) } /*! - \property QDateTimeEdit::minimumDateTime \since 4.4 + \property QDateTimeEdit::minimumDateTime \brief the minimum datetime of the date time edit - When setting this property the \l maximumDateTime() is adjusted if - necessary to ensure that the range remains valid. If the datetime is - not a valid QDateTime object, this function does nothing. + Changing this property implicitly updates the \l minimumDate and \l + minimumTime properties to the date and time parts of this property, + respectively. When setting this property, the \l maximumDateTime is adjusted, + if necessary, to ensure that the range remains valid. Otherwise, changing this + property preserves the \l minimumDateTime property. - The default minimumDateTime can be restored with - clearMinimumDateTime() + This property can only be set to a valid QDateTime value. The earliest + date-time that setMinimumDateTime() accepts is the start of 100 CE. The + property's default is the start of September 14, 1752 CE. This default can be + restored with clearMinimumDateTime(). - By default, this property contains a date that refers to September 14, - 1752 and a time of 00:00:00 and 0 milliseconds. - - \sa maximumDateTime(), minimumTime(), maximumTime(), minimumDate(), - maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(), - clearMaximumDateTime(), clearMinimumDate(), - clearMaximumDate(), clearMinimumTime(), clearMaximumTime() + \sa maximumDateTime, minimumTime, minimumDate, setDateTimeRange(), QDateTime::isValid() */ QDateTime QDateTimeEdit::minimumDateTime() const @@ -372,25 +374,23 @@ void QDateTimeEdit::setMinimumDateTime(const QDateTime &dt) } /*! - \property QDateTimeEdit::maximumDateTime \since 4.4 + \property QDateTimeEdit::maximumDateTime \brief the maximum datetime of the date time edit - When setting this property the \l minimumDateTime() is adjusted if - necessary to ensure that the range remains valid. If the datetime is - not a valid QDateTime object, this function does nothing. + Changing this property implicitly updates the \l maximumDate and \l + maximumTime properties to the date and time parts of this property, + respectively. When setting this property, the \l minimumDateTime is adjusted, + if necessary, to ensure that the range remains valid. Otherwise, changing this + property preserves the \l minimumDateTime property. - The default maximumDateTime can be restored with + This property can only be set to a valid QDateTime value. The latest + date-time that setMaximumDateTime() accepts is the end of 9999 CE. This is the + default for this property. This default can be restored with clearMaximumDateTime(). - By default, this property contains a date that refers to 31 December, - 9999 and a time of 23:59:59 and 999 milliseconds. - - \sa minimumDateTime(), minimumTime(), maximumTime(), minimumDate(), - maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(), - clearMinimumDateTime(), clearMinimumDate(), - clearMaximumDate(), clearMinimumTime(), clearMaximumTime() + \sa minimumDateTime, maximumTime, maximumDate(), setDateTimeRange(), QDateTime::isValid() */ QDateTime QDateTimeEdit::maximumDateTime() const @@ -414,11 +414,12 @@ void QDateTimeEdit::setMaximumDateTime(const QDateTime &dt) } } - /*! - Convenience function to set minimum and maximum date time with one - function call. \since 4.4 + \brief Set the range of allowed date-times for the date time edit. + + This convenience function sets the \l minimumDateTime and \l maximumDateTime + properties. \snippet code/src_gui_widgets_qdatetimeedit.cpp 1 @@ -426,21 +427,18 @@ void QDateTimeEdit::setMaximumDateTime(const QDateTime &dt) \snippet code/src_gui_widgets_qdatetimeedit.cpp 2 - If either \a min or \a max are not valid, this function does - nothing. + If either \a min or \a max is invalid, this function does nothing. If \a max + is less than \a min, \a min is used also as \a max. - \sa setMinimumDate(), maximumDate(), setMaximumDate(), - clearMinimumDate(), setMinimumTime(), maximumTime(), - setMaximumTime(), clearMinimumTime(), QDateTime::isValid() + \sa minimumDateTime, maximumDateTime, setDateRange(), setTimeRange(), QDateTime::isValid() */ void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max) { Q_D(QDateTimeEdit); + // FIXME: does none of the range checks applied to setMin/setMax methods ! const QDateTime minimum = min.toTimeSpec(d->spec); - QDateTime maximum = max.toTimeSpec(d->spec); - if (min > max) - maximum = minimum; + const QDateTime maximum = (min > max ? minimum : max.toTimeSpec(d->spec)); d->setRange(minimum, maximum); } @@ -449,15 +447,20 @@ void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max) \brief the minimum date of the date time edit - When setting this property the \l maximumDate is adjusted if - necessary, to ensure that the range remains valid. If the date is - not a valid QDate object, this function does nothing. + Changing this property updates the date of the \l minimumDateTime property + while preserving the \l minimumTime property. When setting this property, + the \l maximumDate is adjusted, if necessary, to ensure that the range remains + valid. When this happens, the \l maximumTime property is also adjusted if it + is less than the \l minimumTime property. Otherwise, changes to this property + preserve the \l maximumDateTime property. - By default, this property contains a date that refers to September 14, 1752. - The minimum date must be at least the first day in year 100, otherwise - setMinimumDate() has no effect. + This property can only be set to a valid QDate object describing a date on + which the current \l minimumTime property makes a valid QDateTime object. The + earliest date that setMinimumDate() accepts is the start of 100 CE. The + default for this property is September 14, 1752 CE. This default can be + restored with clearMinimumDateTime(). - \sa minimumTime(), maximumTime(), setDateRange() + \sa maximumDate, minimumTime, minimumDateTime, setDateRange(), QDate::isValid() */ QDate QDateTimeEdit::minimumDate() const @@ -484,13 +487,20 @@ void QDateTimeEdit::clearMinimumDate() \brief the maximum date of the date time edit - When setting this property the \l minimumDate is adjusted if - necessary to ensure that the range remains valid. If the date is - not a valid QDate object, this function does nothing. + Changing this property updates the date of the \l maximumDateTime property + while preserving the \l maximumTime property. When setting this property, the + \l minimumDate is adjusted, if necessary, to ensure that the range remains + valid. When this happens, the \l minimumTime property is also adjusted if it + is greater than the \l maximumTime property. Otherwise, changes to this + property preserve the \l minimumDateTime property. - By default, this property contains a date that refers to December 31, 9999. + This property can only be set to a valid QDate object describing a date on + which the current \l maximumTime property makes a valid QDateTime object. The + latest date that setMaximumDate() accepts is the end of 9999 CE. This is the + default for this property. This default can be restored with + clearMaximumDateTime(). - \sa minimumDate, minimumTime, maximumTime, setDateRange() + \sa minimumDate, maximumTime, maximumDateTime, setDateRange(), QDate::isValid() */ QDate QDateTimeEdit::maximumDate() const @@ -502,9 +512,8 @@ QDate QDateTimeEdit::maximumDate() const void QDateTimeEdit::setMaximumDate(const QDate &max) { Q_D(QDateTimeEdit); - if (max.isValid()) { + if (max.isValid()) setMaximumDateTime(QDateTime(max, d->maximum.toTime(), d->spec)); - } } void QDateTimeEdit::clearMaximumDate() @@ -517,13 +526,18 @@ void QDateTimeEdit::clearMaximumDate() \brief the minimum time of the date time edit - When setting this property the \l maximumTime is adjusted if - necessary, to ensure that the range remains valid. If the time is - not a valid QTime object, this function does nothing. + Changing this property updates the time of the \l minimumDateTime property + while preserving the \l minimumDate and \l maximumDate properties. If those + date properties coincide, when setting this property, the \l maximumTime + property is adjusted, if necessary, to ensure that the range remains + valid. Otherwise, changing this property preserves the \l maximumDateTime + property. - By default, this property contains a time of 00:00:00 and 0 milliseconds. + This property can be set to any valid QTime value. By default, this property + contains a time of 00:00:00 and 0 milliseconds. This default can be restored + with clearMinimumTime(). - \sa maximumTime, minimumDate, maximumDate, setTimeRange() + \sa maximumTime, minimumDate, minimumDateTime, setTimeRange(), QTime::isValid() */ QTime QDateTimeEdit::minimumTime() const @@ -551,13 +565,18 @@ void QDateTimeEdit::clearMinimumTime() \brief the maximum time of the date time edit - When setting this property, the \l minimumTime is adjusted if - necessary to ensure that the range remains valid. If the time is - not a valid QTime object, this function does nothing. + Changing this property updates the time of the \l maximumDateTime property + while preserving the \l minimumDate and \l maximumDate properties. If those + date properties coincide, when setting this property, the \l minimumTime + property is adjusted, if necessary, to ensure that the range remains + valid. Otherwise, changing this property preserves the \l minimumDateTime + property. - By default, this property contains a time of 23:59:59 and 999 milliseconds. + This property can be set to any valid QTime value. By default, this property + contains a time of 23:59:59 and 999 milliseconds. This default can be restored + with clearMaximumTime(). - \sa minimumTime, minimumDate, maximumDate, setTimeRange() + \sa minimumTime, maximumDate, maximumDateTime, setTimeRange(), QTime::isValid() */ QTime QDateTimeEdit::maximumTime() const { @@ -580,8 +599,10 @@ void QDateTimeEdit::clearMaximumTime() } /*! - Convenience function to set minimum and maximum date with one - function call. + \brief Set the range of allowed dates for the date time edit. + + This convenience function sets the \l minimumDate and \l maximumDate + properties. \snippet code/src_gui_widgets_qdatetimeedit.cpp 3 @@ -589,12 +610,14 @@ void QDateTimeEdit::clearMaximumTime() \snippet code/src_gui_widgets_qdatetimeedit.cpp 4 - If either \a min or \a max are not valid, this function does - nothing. + If either \a min or \a max is invalid, this function does nothing. This + function preserves the \l minimumTime property. If \a max is less than \a min, + the new maximumDateTime property shall be the new minimumDateTime property. If + \a max is equal to \a min and the \l maximumTime property was less then the \l + minimumTime property, the \l maximumTime property is set to the \l minimumTime + property. Otherwise, this preserves the \l maximumTime property. - \sa setMinimumDate(), maximumDate(), setMaximumDate(), - clearMinimumDate(), setMinimumTime(), maximumTime(), - setMaximumTime(), clearMinimumTime(), QDate::isValid() + \sa minimumDate, maximumDate, setDateTimeRange(), QDate::isValid() */ void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max) @@ -607,8 +630,16 @@ void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max) } /*! - Convenience function to set minimum and maximum time with one - function call. + \brief Set the range of allowed times for the date time edit. + + This convenience function sets the \l minimumTime and \l maximumTime + properties. + + Note that these only constrain the date time edit's value on, + respectively, the \l minimumDate and \l maximumDate. When these date + properties do not coincide, times after \a maximumTime are allowed on dates + before \l maximumDate and times before \a minimumTime are allowed on dates + after \l minimumDate. \snippet code/src_gui_widgets_qdatetimeedit.cpp 5 @@ -616,12 +647,11 @@ void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max) \snippet code/src_gui_widgets_qdatetimeedit.cpp 6 - If either \a min or \a max are not valid, this function does - nothing. + If either \a min or \a max is invalid, this function does nothing. This + function preserves the \l minimumDate and \l maximumDate properties. If those + properties coincide and max is \a less than \a min, \a min is used as \a max. - \sa setMinimumDate(), maximumDate(), setMaximumDate(), - clearMinimumDate(), setMinimumTime(), maximumTime(), - setMaximumTime(), clearMinimumTime(), QTime::isValid() + \sa minimumTime, maximumTime, setDateTimeRange(), QTime::isValid() */ void QDateTimeEdit::setTimeRange(const QTime &min, const QTime &max) @@ -865,7 +895,7 @@ QString QDateTimeEdit::sectionText(Section section) const Note that if you specify a two digit year, it will be interpreted to be in the century in which the date time edit was initialized. - The default century is the 21 (2000-2099). + The default century is the 21st (2000-2099). If you specify an invalid format the format will not be set. diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index 0d2568b85d..bd5e0b047e 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -1216,8 +1216,8 @@ QMargins QLineEdit::textMargins() const \row \li \c a \li ASCII alphabetic character permitted but not required. \row \li \c N \li ASCII alphanumeric character required. A-Z, a-z, 0-9. \row \li \c n \li ASCII alphanumeric character permitted but not required. - \row \li \c X \li Any character required. - \row \li \c x \li Any character permitted but not required. + \row \li \c X \li Any non-blank character required. + \row \li \c x \li Any non-blank character permitted but not required. \row \li \c 9 \li ASCII digit required. 0-9. \row \li \c 0 \li ASCII digit permitted but not required. \row \li \c D \li ASCII digit required. 1-9. diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index ddcd022fb6..fc7e2dbbcb 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -792,6 +792,8 @@ void QMenuSloppyState::setSubMenuPopup(const QRect &actionRect, QAction *resetAc m_use_reset_action = true; m_time.stop(); m_action_rect = actionRect; + if (m_sub_menu) + QMenuPrivate::get(m_sub_menu)->sloppyState.m_parent = nullptr; m_sub_menu = subMenu; QMenuPrivate::get(subMenu)->sloppyState.m_parent = this; m_reset_action = resetAction; diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index a50068b5a0..59c8af30b4 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -846,7 +846,8 @@ QMenu *QMenuBar::addMenu(const QIcon &icon, const QString &title) } /*! - Appends \a menu to the menu bar. Returns the menu's menuAction(). + Appends \a menu to the menu bar. Returns the menu's menuAction(). The menu bar + does not take ownership of the menu. \note The returned QAction object can be used to hide the corresponding menu. diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index 1856f0296b..0bfaa767c6 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -2328,6 +2328,7 @@ void QPlainTextEdit::changeEvent(QEvent *e) d->autoScrollTimer.stop(); } else if (e->type() == QEvent::EnabledChange) { e->setAccepted(isEnabled()); + d->control->setPalette(palette()); d->sendControlEvent(e); } else if (e->type() == QEvent::PaletteChange) { d->control->setPalette(palette()); diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index a242947c11..9dd61c2c6a 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -1090,7 +1090,7 @@ bool QWidgetLineControl::isValidInput(QChar key, QChar mask) const return true; break; case 'X': - if (key.isPrint()) + if (key.isPrint() && key != m_blank) return true; break; case 'x': diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index ce807c9f75..49a1a02867 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -1283,6 +1283,8 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e) } else { QTextCursor localCursor = cursor; localCursor.deletePreviousChar(); + if (cursor.d) + cursor.d->setX(); } goto accept; } @@ -1322,9 +1324,13 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e) else if (e == QKeySequence::Delete) { QTextCursor localCursor = cursor; localCursor.deleteChar(); + if (cursor.d) + cursor.d->setX(); } else if (e == QKeySequence::Backspace) { QTextCursor localCursor = cursor; localCursor.deletePreviousChar(); + if (cursor.d) + cursor.d->setX(); }else if (e == QKeySequence::DeleteEndOfWord) { if (!cursor.hasSelection()) cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor); diff --git a/tests/auto/corelib/global/qglobal/qglobal.c b/tests/auto/corelib/global/qglobal/qglobal.c index c7124454d0..7a2266ae94 100644 --- a/tests/auto/corelib/global/qglobal/qglobal.c +++ b/tests/auto/corelib/global/qglobal/qglobal.c @@ -28,7 +28,7 @@ #include -#if QT_HAS_INCLUDE() || __STDC_VERSION__ >= 199901L +#if __has_include() || __STDC_VERSION__ >= 199901L # include #else # undef true diff --git a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp index 4ca68550b9..4e105d7dc7 100644 --- a/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp +++ b/tests/auto/corelib/kernel/qdeadlinetimer/tst_qdeadlinetimer.cpp @@ -32,7 +32,7 @@ #include #include -#if QT_HAS_INCLUDE() +#if __has_include() # include #endif @@ -519,7 +519,7 @@ void tst_QDeadlineTimer::expire() void tst_QDeadlineTimer::stdchrono() { -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("std::chrono not found on this system"); #else using namespace std::chrono; diff --git a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp index 49c10c6a24..365508024b 100644 --- a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp +++ b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp @@ -67,6 +67,7 @@ private slots: void sendPostedEvents_data(); void sendPostedEvents(); void processEventsOnlySendsQueuedEvents(); + void eventLoopExit(); }; bool tst_QEventDispatcher::event(QEvent *e) @@ -314,5 +315,49 @@ void tst_QEventDispatcher::processEventsOnlySendsQueuedEvents() QCOMPARE(object.eventsReceived, 4); } +void tst_QEventDispatcher::eventLoopExit() +{ + // This test was inspired by QTBUG-79477. A particular + // implementation detail in QCocoaEventDispatcher allowed + // QEventLoop::exit() to fail to really exit the event loop. + // Thus this test is a part of the dispatcher auto-test. + + // Imitates QApplication::exec(): + QEventLoop mainLoop; + // The test itself is a lambda: + QTimer::singleShot(0, [&mainLoop]() { + // Two more single shots, both will be posted as events + // (zero timeout) and supposed to be processes by the + // mainLoop: + + QTimer::singleShot(0, [&mainLoop]() { + // wakeUp triggers QCocoaEventDispatcher into incrementing + // its 'serialNumber': + mainLoop.wakeUp(); + // QCocoaEventDispatcher::processEvents() will process + // posted events and execute the second lambda defined below: + QCoreApplication::processEvents(); + }); + + QTimer::singleShot(0, [&mainLoop]() { + // With QCocoaEventDispatcher this is executed while in the + // processEvents (see above) and would fail to actually + // interrupt the loop. + mainLoop.exit(); + }); + }); + + bool timeoutObserved = false; + QTimer::singleShot(500, [&timeoutObserved, &mainLoop]() { + // In case the QEventLoop::exit above failed, we have to bail out + // early, not wasting time: + mainLoop.exit(); + timeoutObserved = true; + }); + + mainLoop.exec(); + QVERIFY(!timeoutObserved); +} + QTEST_MAIN(tst_QEventDispatcher) #include "tst_qeventdispatcher.moc" diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 8e0bdac520..1bd27cd0ce 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -223,7 +223,7 @@ void tst_QTimer::remainingTimeDuringActivation() namespace { -#if QT_HAS_INCLUDE() +#if __has_include() template std::chrono::milliseconds to_ms(T t) { return std::chrono::duration_cast(t); } @@ -233,7 +233,7 @@ namespace { void tst_QTimer::basic_chrono() { -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("This test requires C++11 support"); #else // duplicates zeroTimer, singleShotTimeout, interval and remainingTime @@ -871,7 +871,7 @@ void tst_QTimer::singleShotToFunctors() void tst_QTimer::singleShot_chrono() { -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("This test requires C++11 support"); #else // duplicates singleShotStaticFunctionZeroTimeout and singleShotToFunctors diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index c4af2267a8..8db28c7c71 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -45,7 +45,7 @@ #include #include #include -#if QT_HAS_INCLUDE() && __cplusplus >= 201703L +#if __has_include() && __cplusplus >= 201703L #include #endif #include @@ -4568,7 +4568,7 @@ void tst_QVariant::accessSequentialContainerKey() void tst_QVariant::fromStdVariant() { -#if QT_HAS_INCLUDE() && __cplusplus >= 201703L +#if __has_include() && __cplusplus >= 201703L { typedef std::variant intorbool_t; intorbool_t stdvar = 5; diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index 47ad328d64..d5a9012f9f 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -384,7 +384,7 @@ void tst_QCborValue::copyCompare() QCOMPARE(v, other); QVERIFY(!(v != other)); QVERIFY(!(v < other)); -#if 0 && QT_HAS_INCLUDE() +#if 0 && __has_include() QVERIFY(v <= other); QVERIFY(v >= other); QVERIFY(!(v > other)); @@ -821,9 +821,37 @@ void tst_QCborValue::mapMutation() QVERIFY(v.isUndefined()); // now mutate the list + // simple -> HasByteData + const QString strValue = QStringLiteral("value"); + v = strValue; + QVERIFY(v.isString()); + QCOMPARE(v, QCborValue(strValue)); + QCOMPARE(m, QCborMap({{42, strValue}})); + + // HasByteData -> HasByteData + const QLatin1String otherStrValue("othervalue"); + v = otherStrValue; + QVERIFY(v.isString()); + QCOMPARE(v, QCborValue(otherStrValue)); + QCOMPARE(m, QCborMap({{42, otherStrValue}})); + + // HasByteData -> simple + v = 42; + QVERIFY(v.isInteger()); + QCOMPARE(v, QCborValue(42)); + QCOMPARE(m, QCborMap({{42, 42}})); + + // simple -> container + v = QCborArray{1, 2, 3}; + QVERIFY(v.isArray()); + QCOMPARE(v, QCborArray({1, 2, 3})); + QCOMPARE(m, QCborMap({{42, QCborArray{1, 2, 3}}})); + + // container -> simple v = true; QVERIFY(v.isBool()); QVERIFY(v.isTrue()); + QCOMPARE(m, QCborMap({{42, true}})); QVERIFY(m.begin()->isTrue()); QVERIFY(m.begin().value() == v); QVERIFY(v == m.begin().value()); diff --git a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp index 749aa45916..11f34343ab 100644 --- a/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/auto/corelib/thread/qmutex/tst_qmutex.cpp @@ -89,7 +89,7 @@ enum { waitTime = 100 }; -#if QT_HAS_INCLUDE() +#if __has_include() static Q_CONSTEXPR std::chrono::milliseconds waitTimeAsDuration(waitTime); #endif @@ -100,7 +100,7 @@ void tst_QMutex::convertToMilliseconds_data() QTest::addColumn("intValue"); QTest::addColumn("expected"); -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("This test requires "); #endif @@ -156,7 +156,7 @@ void tst_QMutex::convertToMilliseconds_data() void tst_QMutex::convertToMilliseconds() { -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("This test requires "); #else QFETCH(TimeUnit, unit); @@ -325,7 +325,7 @@ void tst_QMutex::tryLock_non_recursive() } void tst_QMutex::try_lock_for_non_recursive() { -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("This test requires "); #else class Thread : public QThread @@ -454,7 +454,7 @@ void tst_QMutex::try_lock_for_non_recursive() { void tst_QMutex::try_lock_until_non_recursive() { -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("This test requires "); #else class Thread : public QThread @@ -707,7 +707,7 @@ void tst_QMutex::tryLock_recursive() void tst_QMutex::try_lock_for_recursive() { -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("This test requires "); #else class Thread : public QThread @@ -836,7 +836,7 @@ void tst_QMutex::try_lock_for_recursive() void tst_QMutex::try_lock_until_recursive() { -#if !QT_HAS_INCLUDE() +#if !__has_include() QSKIP("This test requires "); #else class Thread : public QThread diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index 7f13fd0aa5..7778542736 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -150,6 +150,7 @@ private slots: void timeZones() const; void systemTimeZoneChange() const; + void invalid_data() const; void invalid() const; void range() const; @@ -2209,6 +2210,13 @@ void tst_QDateTime::fromStringDateFormat_data() << Qt::TextDate << QDateTime(QDate(2013, 5, 6), QTime(1, 2, 3, 456)); // Test Qt::ISODate format. + QTest::newRow("trailing space") // QTBUG-80445 + << QString("2000-01-02 03:04:05.678 ") + << Qt::ISODate << QDateTime(QDate(2000, 1, 2), QTime(3, 4, 5, 678)); + QTest::newRow("space before millis") + << QString("2000-01-02 03:04:05. 678") << Qt::ISODate << QDateTime(); + + // Normal usage: QTest::newRow("ISO +01:00") << QString::fromLatin1("1987-02-13T13:24:51+01:00") << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC); QTest::newRow("ISO +00:01") << QString::fromLatin1("1987-02-13T13:24:51+00:01") @@ -2229,11 +2237,17 @@ void tst_QDateTime::fromStringDateFormat_data() << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9), Qt::UTC); QTest::newRow("ISO zzz-3") << QString::fromLatin1("2014-12-15T12:37:09.745-3") << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9, 745), Qt::UTC); + QTest::newRow("ISO lower-case") << QString::fromLatin1("2005-06-28T07:57:30.002z") + << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), Qt::UTC); // No time specified - defaults to Qt::LocalTime. QTest::newRow("ISO data3") << QString::fromLatin1("2002-10-01") << Qt::ISODate << QDateTime(QDate(2002, 10, 1), QTime(0, 0, 0, 0), Qt::LocalTime); + // Excess digits in milliseconds, round correctly: QTest::newRow("ISO") << QString::fromLatin1("2005-06-28T07:57:30.0010000000Z") << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC); + QTest::newRow("ISO rounding") << QString::fromLatin1("2005-06-28T07:57:30.0015Z") + << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), Qt::UTC); + // ... and accept comma as separator: QTest::newRow("ISO with comma 1") << QString::fromLatin1("2005-06-28T07:57:30,0040000000Z") << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 4), Qt::UTC); QTest::newRow("ISO with comma 2") << QString::fromLatin1("2005-06-28T07:57:30,0015Z") @@ -2458,6 +2472,7 @@ void tst_QDateTime::fromStringStringFormat_data() if (southBrazil.isValid()) { QTest::newRow("spring-forward-midnight") << QString("2008-10-19 23:45.678 America/Sao_Paulo") << QString("yyyy-MM-dd mm:ss.zzz t") + // That's in the hour skipped - expect the matching time after the spring-forward, in DST: << QDateTime(QDate(2008, 10, 19), QTime(1, 23, 45, 678), southBrazil); } #endif @@ -3359,6 +3374,9 @@ void tst_QDateTime::timeZones() const QCOMPARE(utc.date(), utcDst.date()); QCOMPARE(utc.time(), utcDst.time()); + // Crash test, QTBUG-80146: + QVERIFY(!nzStd.toTimeZone(QTimeZone()).isValid()); + // Sydney is 2 hours behind New Zealand QTimeZone ausTz = QTimeZone("Australia/Sydney"); QDateTime aus = nzStd.toTimeZone(ausTz); @@ -3528,23 +3546,42 @@ void tst_QDateTime::systemTimeZoneChange() const QCOMPARE(tzDate.toMSecsSinceEpoch(), tzMsecs); } +void tst_QDateTime::invalid_data() const +{ + QTest::addColumn("when"); + QTest::addColumn("spec"); + QTest::addColumn("goodZone"); + QTest::newRow("default") << QDateTime() << Qt::LocalTime << true; + + QDateTime invalidDate = QDateTime(QDate(0, 0, 0), QTime(-1, -1, -1)); + QTest::newRow("simple") << invalidDate << Qt::LocalTime << true; + QTest::newRow("UTC") << invalidDate.toUTC() << Qt::UTC << true; + QTest::newRow("offset") + << invalidDate.toOffsetFromUtc(3600) << Qt::OffsetFromUTC << true; + QTest::newRow("CET") + << invalidDate.toTimeZone(QTimeZone("Europe/Oslo")) << Qt::TimeZone << true; + + // Crash tests, QTBUG-80146: + QTest::newRow("nozone+construct") + << QDateTime(QDate(1970, 1, 1), QTime(12, 0), QTimeZone()) << Qt::TimeZone << false; + QTest::newRow("nozone+fromMSecs") + << QDateTime::fromMSecsSinceEpoch(42, QTimeZone()) << Qt::TimeZone << false; + QDateTime valid(QDate(1970, 1, 1), QTime(12, 0), Qt::UTC); + QTest::newRow("tonozone") << valid.toTimeZone(QTimeZone()) << Qt::TimeZone << false; +} + void tst_QDateTime::invalid() const { - QDateTime invalidDate = QDateTime(QDate(0, 0, 0), QTime(-1, -1, -1)); - QCOMPARE(invalidDate.isValid(), false); - QCOMPARE(invalidDate.timeSpec(), Qt::LocalTime); - - QDateTime utcDate = invalidDate.toUTC(); - QCOMPARE(utcDate.isValid(), false); - QCOMPARE(utcDate.timeSpec(), Qt::UTC); - - QDateTime offsetDate = invalidDate.toOffsetFromUtc(3600); - QCOMPARE(offsetDate.isValid(), false); - QCOMPARE(offsetDate.timeSpec(), Qt::OffsetFromUTC); - - QDateTime tzDate = invalidDate.toTimeZone(QTimeZone("Europe/Oslo")); - QCOMPARE(tzDate.isValid(), false); - QCOMPARE(tzDate.timeSpec(), Qt::TimeZone); + QFETCH(QDateTime, when); + QFETCH(Qt::TimeSpec, spec); + QFETCH(bool, goodZone); + QVERIFY(!when.isValid()); + QCOMPARE(when.timeSpec(), spec); + QCOMPARE(when.timeZoneAbbreviation(), QString()); + if (!goodZone) + QCOMPARE(when.toMSecsSinceEpoch(), 0); + QVERIFY(!when.isDaylightTime()); + QCOMPARE(when.timeZone().isValid(), goodZone); } void tst_QDateTime::range() const diff --git a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp index f6f10e9642..0e4517e740 100644 --- a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp +++ b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp @@ -51,7 +51,7 @@ #ifdef Q_CC_MSVC #define COMPILER_HAS_STDLIB_INCLUDE(x) 1 #else -#define COMPILER_HAS_STDLIB_INCLUDE(x) QT_HAS_INCLUDE(x) +#define COMPILER_HAS_STDLIB_INCLUDE(x) __has_include(x) #endif #if COMPILER_HAS_STDLIB_INCLUDE() diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp index 0e9f94ab2b..3917c859cc 100644 --- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp +++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp @@ -125,6 +125,7 @@ private slots: void clonePreservesResources(); void clonePreservesUserStates(); void clonePreservesIndentWidth(); + void clonePreservesFormatsWhenEmpty(); void blockCount(); void defaultStyleSheet(); @@ -2348,6 +2349,32 @@ void tst_QTextDocument::clonePreservesIndentWidth() delete clone; } +void tst_QTextDocument::clonePreservesFormatsWhenEmpty() +{ + QTextDocument document; + QTextCursor cursor(&document); + + // Change a few char format attributes + QTextCharFormat charFormat; + charFormat.setFontPointSize(charFormat.fontPointSize() + 1); + charFormat.setFontWeight(charFormat.fontWeight() + 1); + cursor.setBlockCharFormat(charFormat); + + // Change a few block format attributes + QTextBlockFormat blockFormat; + blockFormat.setAlignment(Qt::AlignRight); // The default is Qt::AlignLeft + blockFormat.setIndent(blockFormat.indent() + 1); + cursor.setBlockFormat(blockFormat); + + auto clone = document.clone(); + QTextCursor cloneCursor(clone); + + QCOMPARE(cloneCursor.blockCharFormat().fontPointSize(), charFormat.fontPointSize()); + QCOMPARE(cloneCursor.blockCharFormat().fontWeight(), charFormat.fontWeight()); + QCOMPARE(cloneCursor.blockFormat().alignment(), blockFormat.alignment()); + QCOMPARE(cloneCursor.blockFormat().indent(), blockFormat.indent()); +} + void tst_QTextDocument::blockCount() { QCOMPARE(doc->blockCount(), 1); diff --git a/tests/auto/network/kernel/qnetworkinterface/BLACKLIST b/tests/auto/network/kernel/qnetworkinterface/BLACKLIST deleted file mode 100644 index e28cc38ee0..0000000000 --- a/tests/auto/network/kernel/qnetworkinterface/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -# QTBUG-65667 -[localAddress:linklocal-ipv4] -windows ci diff --git a/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp b/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp index 0c7ba99be5..bc6e5435df 100644 --- a/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp +++ b/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp @@ -215,31 +215,45 @@ void tst_QNetworkInterface::loopbackIPv6() } void tst_QNetworkInterface::localAddress_data() { + bool ipv6 = isIPv6Working(); QTest::addColumn("target"); QTest::newRow("localhost-ipv4") << QHostAddress(QHostAddress::LocalHost); - if (isIPv6Working()) + if (ipv6) QTest::newRow("localhost-ipv6") << QHostAddress(QHostAddress::LocalHostIPv6); QTest::newRow("test-server") << QtNetworkSettings::serverIP(); - // Since we don't actually transmit anything, we can list any IPv4 address - // and it should work. But we're using a linklocal address so that this - // test can pass even machines that failed to reach a DHCP server. - QTest::newRow("linklocal-ipv4") << QHostAddress("169.254.0.1"); + QSet added; + const QList ifaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &iface : ifaces) { + if ((iface.flags() & QNetworkInterface::IsUp) == 0) + continue; + const QList addrs = iface.addressEntries(); + for (const QNetworkAddressEntry &entry : addrs) { + QHostAddress addr = entry.ip(); + if (addr.isLoopback()) + continue; // added above - if (isIPv6Working()) { - // On the other hand, we can't list just any IPv6 here. It's very - // likely that this machine has not received a route via ICMPv6-RA or - // DHCPv6, so it won't have a global route. On some OSes, IPv6 may be - // enabled per interface, so we need to know which ones work. - const QList addrs = QNetworkInterface::allAddresses(); - for (const QHostAddress &addr : addrs) { - QString scope = addr.scopeId(); - if (scope.isEmpty()) + if (addr.protocol() == QAbstractSocket::IPv4Protocol) { + // add an IPv4 address with bits in the host portion of the address flipped + quint32 ip4 = entry.ip().toIPv4Address(); + addr.setAddress(ip4 ^ ~entry.netmask().toIPv4Address()); + } else if (!ipv6 || entry.prefixLength() != 64) { continue; - QTest::addRow("linklocal-ipv6-%s", qPrintable(scope)) - << QHostAddress("fe80::1234%" + scope); + } else { + // add a random node in this IPv6 network + quint64 randomid = qFromBigEndian(Q_UINT64_C(0x8f41f072e5733caa)); + QIPv6Address ip6 = addr.toIPv6Address(); + memcpy(&ip6[8], &randomid, sizeof(randomid)); + addr.setAddress(ip6); + } + + if (added.contains(addr)) + continue; + added.insert(addr); + + QTest::addRow("%s-%s", qPrintable(iface.name()), qPrintable(addr.toString())) << addr; } } } diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index 4c3749eaee..4533284a0f 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -965,9 +965,7 @@ void tst_QSqlQuery::blob() //don' make it too big otherwise sybase and mysql will complain QByteArray ba( BLOBSIZE, 0 ); - int i; - - for ( i = 0; i < ( int )ba.size(); ++i ) + for (int i = 0; i < ba.size(); ++i) ba[i] = i % 256; QSqlQuery q( db ); @@ -980,7 +978,7 @@ void tst_QSqlQuery::blob() QVERIFY_SQL(q, prepare("insert into " + qTableName("qtest_blob", __FILE__, db) + " (id, t_blob) values (?, ?)")); - for ( i = 0; i < BLOBCOUNT; ++i ) { + for (int i = 0; i < BLOBCOUNT; ++i) { q.addBindValue( i ); q.addBindValue( ba ); QVERIFY_SQL( q, exec() ); @@ -988,13 +986,13 @@ void tst_QSqlQuery::blob() QVERIFY_SQL(q, exec("select * from " + qTableName("qtest_blob", __FILE__, db))); - for ( i = 0; i < BLOBCOUNT; ++i ) { + for (int i = 0; i < BLOBCOUNT; ++i) { QVERIFY( q.next() ); QByteArray res = q.value( 1 ).toByteArray(); QVERIFY2( res.size() >= ba.size(), QString( "array sizes differ, expected %1, got %2" ).arg( ba.size() ).arg( res.size() ).toLatin1() ); - for ( int i2 = 0; i2 < ( int )ba.size(); ++i2 ) { + for (int i2 = 0; i2 < ba.size(); ++i2) { if ( res[i2] != ba[i2] ) QFAIL( QString( "ByteArrays differ at position %1, expected %2, got %3" ).arg( i2 ).arg(( int )( unsigned char )ba[i2] ).arg(( int )( unsigned char )res[i2] ).toLatin1() ); @@ -1834,7 +1832,7 @@ void tst_QSqlQuery::oci_rawField() } // test whether we can fetch values with more than DOUBLE precision -// note that MySQL's 3.x highest precision is that of a double, although +// note that SQLite highest precision is that of a double, although // you can define field with higher precision void tst_QSqlQuery::precision() { @@ -1845,46 +1843,41 @@ void tst_QSqlQuery::precision() if (dbType == QSqlDriver::Interbase) QSKIP("DB unable to store high precision"); + const auto oldPrecision = db.driver()->numericalPrecisionPolicy(); + db.driver()->setNumericalPrecisionPolicy(QSql::HighPrecision); const QString qtest_precision(qTableName("qtest_precision", __FILE__, db)); - static const char precStr[] = "1.2345678901234567891"; - const int precStrLen = sizeof(precStr); + static const QLatin1String precStr("1.2345678901234567891"); { // need a new scope for SQLITE QSqlQuery q( db ); q.exec("drop table " + qtest_precision); - if ( tst_Databases::isMSAccess( db ) ) - QVERIFY_SQL( q, exec( "create table " + qtest_precision + " (col1 number)" ) ); + if (tst_Databases::isMSAccess(db)) + QVERIFY_SQL(q, exec("CREATE TABLE " + qtest_precision + " (col1 number)")); else - QVERIFY_SQL( q, exec( "create table " + qtest_precision + " (col1 numeric(21, 20))" ) ); + QVERIFY_SQL(q, exec("CREATE TABLE " + qtest_precision + " (col1 numeric(21, 20))")); - QVERIFY_SQL( q, exec( "insert into " + qtest_precision + " (col1) values (1.2345678901234567891)" ) ); - - QVERIFY_SQL( q, exec( "select * from " + qtest_precision ) ); - QVERIFY( q.next() ); - - QString val = q.value( 0 ).toString(); - - if ( !val.startsWith( "1.2345678901234567891" ) ) { + QVERIFY_SQL(q, exec("INSERT INTO " + qtest_precision + " (col1) VALUES (" + precStr + ")")); + QVERIFY_SQL(q, exec("SELECT * FROM " + qtest_precision)); + QVERIFY(q.next()); + const QString val = q.value(0).toString(); + if (!val.startsWith(precStr)) { int i = 0; - - while ( i < precStrLen && i < val.size() && precStr[i] != 0 && *( precStr + i ) == val[i].toLatin1() ) + while (i < val.size() && precStr[i] != 0 && precStr[i] == val[i].toLatin1()) i++; - // MySQL and TDS have crappy precisions by default - if (dbType == QSqlDriver::MySqlServer) { - if ( i < 17 ) - QWARN( "MySQL didn't return the right precision" ); - } else if (dbType == QSqlDriver::Sybase) { - if ( i < 18 ) - QWARN( "TDS didn't return the right precision" ); + // TDS has crappy precisions by default + if (dbType == QSqlDriver::Sybase) { + if (i < 18) + QWARN("TDS didn't return the right precision"); } else { - QWARN( QString( tst_Databases::dbToString( db ) + " didn't return the right precision (" + - QString::number( i ) + " out of 21), " + val ).toLatin1() ); + QWARN(QString(tst_Databases::dbToString(db) + " didn't return the right precision (" + + QString::number(i) + " out of 21), " + val).toUtf8()); } } } // SQLITE scope + db.driver()->setNumericalPrecisionPolicy(oldPrecision); } void tst_QSqlQuery::nullResult() @@ -2840,10 +2833,11 @@ void tst_QSqlQuery::psql_bindWithDoubleColonCastOperator() QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, next() ); - if ( db.driver()->hasFeature( QSqlDriver::PreparedQueries ) ) - QCOMPARE( q.executedQuery(), QString( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = ? and id2 =? and id3=?" ) ); + // the positional placeholders are converted to named placeholders in executedQuery() + if (db.driver()->hasFeature(QSqlDriver::PreparedQueries)) + QCOMPARE(q.executedQuery(), QString("select sum((fld1 - fld2)::int) from " + tablename + " where id1 = :myid1 and id2 =:myid2 and id3=:myid3")); else - QCOMPARE( q.executedQuery(), QString( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = 1 and id2 =2 and id3=3" ) ); + QCOMPARE(q.executedQuery(), QString("select sum((fld1 - fld2)::int) from " + tablename + " where id1 = 1 and id2 =2 and id3=3")); } void tst_QSqlQuery::psql_specialFloatValues() @@ -4003,8 +3997,8 @@ void tst_QSqlQuery::QTBUG_2192() // Check if retrieved value preserves reported precision int precision = qMax(0, q.record().field("dt").precision()); - int diff = qAbs(q.value(0).toDateTime().msecsTo(dt)); - int keep = qMin(1000, (int)qPow(10.0, precision)); + qint64 diff = qAbs(q.value(0).toDateTime().msecsTo(dt)); + qint64 keep = qMin(1000LL, qRound64(qPow(10.0, precision))); QVERIFY(diff <= 1000 - keep); } } @@ -4021,8 +4015,10 @@ void tst_QSqlQuery::QTBUG_36211() QSqlQuery q(db); QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (dtwtz timestamptz, dtwotz timestamp)").arg(tableName))); - QTimeZone l_tzBrazil("BRT"); - QTimeZone l_tzChina("CST"); + QTimeZone l_tzBrazil("America/Sao_Paulo"); + QTimeZone l_tzChina("Asia/Shanghai"); + QVERIFY(l_tzBrazil.isValid()); + QVERIFY(l_tzChina.isValid()); QDateTime dt = QDateTime(QDate(2014, 10, 30), QTime(14, 12, 02, 357)); QVERIFY_SQL(q, prepare("INSERT INTO " + tableName + " (dtwtz, dtwotz) VALUES (:dt, :dt)")); q.bindValue(":dt", dt); @@ -4040,8 +4036,8 @@ void tst_QSqlQuery::QTBUG_36211() for (int j = 0; j < 2; ++j) { // Check if retrieved value preserves reported precision int precision = qMax(0, q.record().field(j).precision()); - int diff = qAbs(q.value(j).toDateTime().msecsTo(dt)); - int keep = qMin(1000, (int)qPow(10.0, precision)); + qint64 diff = qAbs(q.value(j).toDateTime().msecsTo(dt)); + qint64 keep = qMin(1000LL, qRound64(qPow(10.0, precision))); QVERIFY(diff <= 1000 - keep); } } diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp index 029738652e..afb24bc528 100644 --- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp @@ -1380,6 +1380,7 @@ void tst_QFiledialog::clearLineEdit() fd.setFileMode(QFileDialog::AnyFile); fd.show(); + QVERIFY(QTest::qWaitForWindowExposed(&fd)); QLineEdit *lineEdit = fd.findChild("fileNameEdit"); QVERIFY(lineEdit); QCOMPARE(lineEdit->text(), QLatin1String("foo")); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 6f8fd5dcbe..dd747a8616 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -227,6 +228,7 @@ private slots: void setFixedSize(); void ensureCreated(); + void createAndDestroy(); void winIdChangeEvent(); void persistentWinId(); void showNativeChild(); @@ -4250,6 +4252,58 @@ public: int winIdChangeEventCount() const { return m_winIdList.count(); } }; +class CreateDestroyWidget : public WinIdChangeWidget +{ +public: + void create() { QWidget::create(); } + void destroy() { QWidget::destroy(); } +}; + +void tst_QWidget::createAndDestroy() +{ + CreateDestroyWidget widget; + + // Create and destroy via QWidget + widget.create(); + QVERIFY(widget.testAttribute(Qt::WA_WState_Created)); + QCOMPARE(widget.winIdChangeEventCount(), 1); + QVERIFY(widget.internalWinId()); + + widget.destroy(); + QVERIFY(!widget.testAttribute(Qt::WA_WState_Created)); + QCOMPARE(widget.winIdChangeEventCount(), 2); + QVERIFY(!widget.internalWinId()); + + // Create via QWidget, destroy via QWindow + widget.create(); + QVERIFY(widget.testAttribute(Qt::WA_WState_Created)); + QCOMPARE(widget.winIdChangeEventCount(), 3); + QVERIFY(widget.internalWinId()); + + widget.windowHandle()->destroy(); + QVERIFY(!widget.testAttribute(Qt::WA_WState_Created)); + QCOMPARE(widget.winIdChangeEventCount(), 4); + QVERIFY(!widget.internalWinId()); + + // Create via QWidget again + widget.create(); + QVERIFY(widget.testAttribute(Qt::WA_WState_Created)); + QCOMPARE(widget.winIdChangeEventCount(), 5); + QVERIFY(widget.internalWinId()); + + // Destroy via QWindow, create via QWindow + widget.windowHandle()->destroy(); + QVERIFY(widget.windowHandle()); + QVERIFY(!widget.testAttribute(Qt::WA_WState_Created)); + QCOMPARE(widget.winIdChangeEventCount(), 6); + QVERIFY(!widget.internalWinId()); + + widget.windowHandle()->create(); + QVERIFY(widget.testAttribute(Qt::WA_WState_Created)); + QCOMPARE(widget.winIdChangeEventCount(), 7); + QVERIFY(widget.internalWinId()); +} + void tst_QWidget::winIdChangeEvent() { { diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index c2475be8b4..bf31f12958 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -885,9 +885,6 @@ void tst_QLineEdit::hasAcceptableInputMask() qApp->sendEvent(testWidget, &lostFocus); QVERIFY(validInput); - // at the moment we don't strip the blank character if it is valid input, this makes the test between x vs X useless - QEXPECT_FAIL( "Any optional and required", "To eat blanks or not? Known issue. Task 43172", Abort); - // test requiredMask testWidget->setInputMask(requiredMask); validInput = true; diff --git a/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp b/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp index 336b6ebfd5..a86784f2ec 100644 --- a/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp +++ b/tests/auto/widgets/widgets/qplaintextedit/tst_qplaintextedit.cpp @@ -155,6 +155,7 @@ private slots: #if QT_CONFIG(scrollbar) void updateAfterChangeCenterOnScroll(); #endif + void updateCursorPositionAfterEdit(); private: void createSelection(); @@ -1802,5 +1803,50 @@ void tst_QPlainTextEdit::updateAfterChangeCenterOnScroll() #endif +void tst_QPlainTextEdit::updateCursorPositionAfterEdit() +{ + QPlainTextEdit plaintextEdit; + plaintextEdit.setPlainText("some text some text\nsome text some text"); + + const auto initialPosition = 1; + + // select some text + auto cursor = plaintextEdit.textCursor(); + cursor.setPosition(initialPosition, QTextCursor::MoveAnchor); + cursor.setPosition(initialPosition + 3, QTextCursor::KeepAnchor); + plaintextEdit.setTextCursor(cursor); + QVERIFY(plaintextEdit.textCursor().hasSelection()); + + QTest::keyClick(&plaintextEdit, Qt::Key_Delete); + QTest::keyClick(&plaintextEdit, Qt::Key_Down); + QTest::keyClick(&plaintextEdit, Qt::Key_Up); + + // Moving the cursor down and up should bring it to the initial position + QCOMPARE(plaintextEdit.textCursor().position(), initialPosition); + + // Test the same with backspace + cursor = plaintextEdit.textCursor(); + cursor.setPosition(initialPosition + 3, QTextCursor::KeepAnchor); + plaintextEdit.setTextCursor(cursor); + QVERIFY(plaintextEdit.textCursor().hasSelection()); + + QTest::keyClick(&plaintextEdit, Qt::Key_Backspace); + QTest::keyClick(&plaintextEdit, Qt::Key_Down); + QTest::keyClick(&plaintextEdit, Qt::Key_Up); + + // Moving the cursor down and up should bring it to the initial position + QCOMPARE(plaintextEdit.textCursor().position(), initialPosition); + + // Test insertion + const QString txt("txt"); + QApplication::clipboard()->setText(txt); + plaintextEdit.paste(); + QTest::keyClick(&plaintextEdit, Qt::Key_Down); + QTest::keyClick(&plaintextEdit, Qt::Key_Up); + + // The curser should move back to the end of the copied text + QCOMPARE(plaintextEdit.textCursor().position(), initialPosition + txt.length()); +} + QTEST_MAIN(tst_QPlainTextEdit) #include "tst_qplaintextedit.moc" diff --git a/tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp b/tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp index 1d47d98657..8f8e8300a1 100644 --- a/tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp +++ b/tests/benchmarks/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp @@ -30,7 +30,7 @@ #include #include #include -#if QT_HAS_INCLUDE() +#if __has_include() #if __cplusplus > 201103L #include #endif diff --git a/tests/manual/highdpi/main.cpp b/tests/manual/highdpi/main.cpp index c025f251a2..2a9fb6aa0c 100644 --- a/tests/manual/highdpi/main.cpp +++ b/tests/manual/highdpi/main.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -51,12 +52,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -64,6 +67,12 @@ #include +static QTextStream &operator<<(QTextStream &str, const QSizeF &s) +{ + str << s.width() << 'x' << s.height(); + return str; +} + static QTextStream &operator<<(QTextStream &str, const QRect &r) { str << r.width() << 'x' << r.height() << Qt::forcesign << r.x() << r.y() << Qt::noforcesign; @@ -1241,7 +1250,7 @@ public: } }; -class MetricsTest : public QWidget +class MetricsTest : public QTabWidget { Q_OBJECT public: @@ -1258,14 +1267,25 @@ QT_SCREEN_SCALE_FACTORS=N;N;N or QT_SCREEN_SCALE_FACTORS=name:N QT_SCALE_FACTOR_ROUNDING_POLICY=Round|Ceil|Floor|RoundPreferFloor|PassThrough QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)"; - resize(480, 360); + m_textEdit = addTextPage("Parameters"); + m_logEdit = addTextPage("Screen Change Log"); - auto layout = new QVBoxLayout(this); + const auto screens = QGuiApplication::screens(); + for (auto screen : screens) + connectScreenChangeSignals(screen); + connect(qApp, &QGuiApplication::screenAdded, this, &MetricsTest::slotScreenAdded); + connect(qApp, &QGuiApplication::primaryScreenChanged, this, &MetricsTest::slotPrimaryScreenChanged); + connect(qApp, &QGuiApplication::screenRemoved, this, &MetricsTest::slotScreenRemoved); - m_textEdit = new QPlainTextEdit; - m_textEdit->setReadOnly(true); - layout->addWidget(m_textEdit); setWindowTitle(formatWindowTitle("Screens")); + m_logTimer.start(); + logMessage(briefFormatScreens()); + + // Resize to roughly match the metrics text. + const auto metrics = QFontMetrics(m_textEdit->font(), m_textEdit); + const int width = 10 + metrics.horizontalAdvance(QStringLiteral("X")) * 50; + const int height = 40 + metrics.height() * (10 + 8 * screens.size()); + resize(width, height); } void setVisible(bool visible) override @@ -1323,15 +1343,118 @@ QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)"; private slots: void screenChanged() { - qDebug().noquote() << __FUNCTION__ << windowHandle()->screen()->name(); + const QString message = QLatin1String("screenChanged ") + windowHandle()->screen()->name(); + qInfo("%s", qPrintable(message)); + logMessage(message); updateMetrics(); } + void slotScreenAdded(QScreen *); + void slotScreenRemoved(QScreen *); + void slotPrimaryScreenChanged(QScreen *); + void slotScreenGeometryChanged(const QRect &geometry) + { logScreenChangeSignal(sender(), "geometry", geometry); } + void slotScreenAvailableGeometryChanged(const QRect &geometry) + { logScreenChangeSignal(sender(), "availableGeometry", geometry); } + void slotScreenPhysicalSizeChanged(const QSizeF &size) + { logScreenChangeSignal(sender(), "physicalSize", size); } + void slotScreenPhysicalDotsPerInchChanged(qreal dpi) + { logScreenChangeSignal(sender(), "physicalDotsPerInch", dpi); } + void slotScreenLogicalDotsPerInchChanged(qreal dpi) + { logScreenChangeSignal(sender(), "logicalDotsPerInch", dpi); } + void slotScreenVirtualGeometryChanged(const QRect &rect) + { logScreenChangeSignal(sender(), "virtualGeometry", rect); } + void slotScreenPrimaryOrientationChanged(Qt::ScreenOrientation orientation) + { logScreenChangeSignal(sender(), "primaryOrientation", orientation); } + void slotScreenOrientationChanged(Qt::ScreenOrientation orientation) + { logScreenChangeSignal(sender(), "orientation", orientation); } + void slotScreenRefreshRateChanged(qreal refreshRate) + { logScreenChangeSignal(sender(), "refreshRate", refreshRate); } + private: + QPlainTextEdit *addTextPage(const QString &title); + void logMessage(const QString &); + void connectScreenChangeSignals(QScreen *s); + static QString briefFormatScreens(); + template + void logScreenChangeSignal(const QObject *o, const char *name, const T &value); + QPlainTextEdit *m_textEdit; + QPlainTextEdit *m_logEdit; + QElapsedTimer m_logTimer; bool m_screenChangedConnected = false; }; +void MetricsTest::slotScreenAdded(QScreen *screen) +{ + logMessage(QLatin1String("Added ") + screen->name() + QLatin1Char(' ') + + briefFormatScreens()); + connectScreenChangeSignals(screen); +} + +void MetricsTest::slotScreenRemoved(QScreen *screen) +{ + logMessage(QLatin1String("Removed ") + screen->name() + QLatin1Char(' ') + + briefFormatScreens()); +} + +void MetricsTest::slotPrimaryScreenChanged(QScreen *screen) +{ + logMessage(QLatin1String("PrimaryScreenChanged ") + screen->name() + QLatin1Char(' ') + + briefFormatScreens()); +} + +QPlainTextEdit *MetricsTest::addTextPage(const QString &title) +{ + auto result = new QPlainTextEdit(this); + result->setReadOnly(true); + result->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + addTab(result, title); + return result; +} + +void MetricsTest::logMessage(const QString &m) +{ + const QString timeStamp = + QStringLiteral("%1ms: %2").arg(m_logTimer.elapsed(), 6, 10, QLatin1Char('0')).arg(m); + m_logEdit->appendPlainText(timeStamp); +} + +void MetricsTest::connectScreenChangeSignals(QScreen *s) +{ + connect(s, &QScreen::geometryChanged, this, &MetricsTest::slotScreenGeometryChanged); + connect(s, &QScreen::availableGeometryChanged, this, &MetricsTest::slotScreenAvailableGeometryChanged); + connect(s, &QScreen::physicalSizeChanged, this, &MetricsTest::slotScreenPhysicalSizeChanged); + connect(s, &QScreen::physicalDotsPerInchChanged, this, &MetricsTest::slotScreenPhysicalDotsPerInchChanged); + connect(s, &QScreen::logicalDotsPerInchChanged, this, &MetricsTest::slotScreenLogicalDotsPerInchChanged); + connect(s, &QScreen::virtualGeometryChanged, this, &MetricsTest::slotScreenVirtualGeometryChanged); + connect(s, &QScreen::primaryOrientationChanged, this, &MetricsTest::slotScreenPrimaryOrientationChanged); + connect(s, &QScreen::orientationChanged, this, &MetricsTest::slotScreenOrientationChanged); + connect(s, &QScreen::refreshRateChanged, this, &MetricsTest::slotScreenRefreshRateChanged); +} + +QString MetricsTest::briefFormatScreens() +{ + QString message; + QTextStream str(&message); + const auto screens = QGuiApplication::screens(); + for (int i = 0, size = screens.size(); i < size; ++i) { + str << (i ? ", " : "("); + str << screens.at(i)->name() << " " << screens.at(i)->geometry(); + } + str << ')'; + return message; +} + +template +void MetricsTest::logScreenChangeSignal(const QObject *o, const char *name, const T &value) +{ + auto screen = qobject_cast(o); + QString message; + QTextStream(&message) << (screen ? screen->name() : QString()) << ' ' << name << " changed: " << value; + logMessage(message); +} + int main(int argc, char **argv) { #define NOSCALINGOPTION "noscaling" diff --git a/tests/testserver/docker-compose-bridge-network.yml b/tests/testserver/docker-compose-bridge-network.yml index 2cabeee1dc..8054d631f8 100644 --- a/tests/testserver/docker-compose-bridge-network.yml +++ b/tests/testserver/docker-compose-bridge-network.yml @@ -1,11 +1,20 @@ version: '2.1' -# The tag of images is used by docker compose file to launch the corresponding -# docker containers. The value of tag comes from the provisioning script -# (coin/provisioning/.../testserver/docker_testserver.sh). The script gets SHA-1 -# of each server context as the tag of docker images. If one of the server -# contexts gets changes, please make sure to update this compose file as well. -# You can run command 'docker images' to list all the tags of test server images. +# The tag of images is used by docker compose file to launch the correct +# docker containers. By default we always launch the "latest" tag. +# +# But in the "docker build" phase, we also tag the images with a unique tag, +# the SHA1 hash of all files used for "docker build" - see sha1tree() in +# provisioning. +# +# So if you want to update the docker image at a specific time, make sure that +# 1. you modify this file to run the specific image's SHA1 tag, instead of +# "latest" +# 2. you build two docker images in provisioning, the currently used one, +# plus the new one that you tag as "latest" +# 3. you switch this file to the "latest" tag when ready + +# You can run `docker images` to list all the tags of available images: # For example: # REPOSITORY TAG # qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13 @@ -20,7 +29,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-apache2:537fe302f61851d1663f41495230d8e3554a4a13 + provisioningImage: qt-test-server-apache2:latest shareDir: ./common serviceDir: ./apache2 entrypoint: service/startup.sh @@ -43,7 +52,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-squid:9c32f41b19aca3d778733c4d8fb0ecc5955e893c + provisioningImage: qt-test-server-squid:latest shareDir: ./common serviceDir: ./squid entrypoint: service/startup.sh @@ -58,7 +67,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-vsftpd:f3a9c8d793a77cc007c0e4e481bec01f9e3eeb7e + provisioningImage: qt-test-server-vsftpd:latest shareDir: ./common serviceDir: ./vsftpd entrypoint: service/startup.sh @@ -77,7 +86,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-ftp-proxy:d7de8b28392d173db512a558ccc84ead8bece2ae + provisioningImage: qt-test-server-ftp-proxy:latest shareDir: ./common serviceDir: ./ftp-proxy entrypoint: service/startup.sh @@ -102,7 +111,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-danted:35607f9b790524cf9690c7d12a9a401696b7b6b5 + provisioningImage: qt-test-server-danted:latest shareDir: ./common serviceDir: ./danted entrypoint: service/startup.sh @@ -117,7 +126,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-cyrus:c8d72754abc0e501afd624ce838e4df35505abc9 + provisioningImage: qt-test-server-cyrus:latest shareDir: ./common serviceDir: ./cyrus entrypoint: service/startup.sh @@ -132,7 +141,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-iptables:cb7a8bd6d28602085a88c8ced7d67e28e75781e2 + provisioningImage: qt-test-server-iptables:latest shareDir: ./common serviceDir: ./iptables entrypoint: service/startup.sh @@ -150,7 +159,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-echo:b29ad409e746a834c1055fd0f7a55fd5056da6ea + provisioningImage: qt-test-server-echo:latest shareDir: ./common serviceDir: ./echo entrypoint: service/startup.sh diff --git a/tests/testserver/docker-compose-host-network.yml b/tests/testserver/docker-compose-host-network.yml index 4b2e1ebdab..aedd94cf73 100644 --- a/tests/testserver/docker-compose-host-network.yml +++ b/tests/testserver/docker-compose-host-network.yml @@ -1,14 +1,7 @@ version: '2.1' -# The tag of images is used by docker compose file to launch the corresponding -# docker containers. The value of tag comes from the provisioning script -# (coin/provisioning/.../testserver/docker_testserver.sh). The script gets SHA-1 -# of each server context as the tag of docker images. If one of the server -# contexts gets changes, please make sure to update this compose file as well. -# You can run command 'docker images' to list all the tags of test server images. -# For example: -# REPOSITORY TAG -# qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13 +# For details about the "latest" tag used in the images here, see comments in +# docker-compose-bridge-network.yml services: apache2: @@ -20,7 +13,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-apache2:537fe302f61851d1663f41495230d8e3554a4a13 + provisioningImage: qt-test-server-apache2:latest shareDir: ./common serviceDir: ./apache2 entrypoint: service/startup.sh @@ -39,7 +32,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-squid:9c32f41b19aca3d778733c4d8fb0ecc5955e893c + provisioningImage: qt-test-server-squid:latest shareDir: ./common serviceDir: ./squid entrypoint: service/startup.sh @@ -54,7 +47,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-vsftpd:f3a9c8d793a77cc007c0e4e481bec01f9e3eeb7e + provisioningImage: qt-test-server-vsftpd:latest shareDir: ./common serviceDir: ./vsftpd entrypoint: service/startup.sh @@ -71,7 +64,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-ftp-proxy:d7de8b28392d173db512a558ccc84ead8bece2ae + provisioningImage: qt-test-server-ftp-proxy:latest shareDir: ./common serviceDir: ./ftp-proxy entrypoint: service/startup.sh @@ -90,7 +83,7 @@ services: build: context: . args: - provisioningImage: qt-test-server-danted:35607f9b790524cf9690c7d12a9a401696b7b6b5 + provisioningImage: qt-test-server-danted:latest shareDir: ./common serviceDir: ./danted entrypoint: service/startup.sh