diff options
54 files changed, 696 insertions, 593 deletions
diff --git a/config.tests/unix/compile.test b/config.tests/unix/compile.test index 69d4285321..bc5258cf4b 100755 --- a/config.tests/unix/compile.test +++ b/config.tests/unix/compile.test @@ -17,6 +17,7 @@ CFLAGS="$SYSROOT_FLAG" CXXFLAGS="$SYSROOT_FLAG" MAC_ARCH_CXXFLAGS="" MAC_ARCH_LFLAGS="" +QMAKE_ARGS= while [ "$#" -gt 0 ]; do PARAM=$1 case $PARAM in @@ -56,7 +57,9 @@ while [ "$#" -gt 0 ]; do CXXFLAGS="$CXXFLAGS $PARAM \"$2\"" shift ;; - *) ;; + *) + QMAKE_ARGS="$QMAKE_ARGS $PARAM" + ;; esac shift done @@ -83,6 +86,7 @@ set -- \ "QMAKE_CFLAGS+=$MAC_ARCH_CFLAGS" \ "QMAKE_CXXFLAGS*=$CXXFLAGS" \ "QMAKE_CXXFLAGS+=$MAC_ARCH_CXXFLAGS" \ + $QMAKE_ARGS \ "$SRCDIR/$TEST/$EXE.pro" \ -o "$OUTDIR/$TEST/Makefile" if [ "$VERBOSE" = "yes" ]; then @@ -4293,8 +4293,12 @@ compileTest() if [ "$CFG_SHARED" = "no" ]; then test_config="$QMAKE_CONFIG static" fi + TEST_CONFIG_FLAGS= + if [ -z "$PKG_CONFIG" ]; then + TEST_CONFIG_FLAGS="QT_CONFIG+=no-pkg-config" + fi echo $ECHO_N "checking for $name... $ECHO_C" - "$unixtests/compile.test" "$XQMAKESPEC" "$test_config" $OPT_VERBOSE "$relpath" "$outpath" "$path" "$name" $I_FLAGS $D_FLAGS $L_FLAGS "$@" + "$unixtests/compile.test" "$XQMAKESPEC" "$test_config" $OPT_VERBOSE "$relpath" "$outpath" "$path" "$name" $I_FLAGS $D_FLAGS $L_FLAGS $TEST_CONFIG_FLAGS "$@" } compileTestWithPkgConfig() @@ -4781,8 +4785,9 @@ for _SQLDR in $CFG_SQL_AVAILABLE; do [ -z "$CFG_MYSQL_CONFIG" ] && CFG_MYSQL_CONFIG=`"$WHICH" mysql_config` if [ -x "$CFG_MYSQL_CONFIG" ]; then QT_CFLAGS_MYSQL=`$CFG_MYSQL_CONFIG --include 2>/dev/null | filterIncludeOptions` - QT_LFLAGS_MYSQL_R=`$CFG_MYSQL_CONFIG --libs_r 2>/dev/null | filterLibraryOptions` - QT_LFLAGS_MYSQL=`$CFG_MYSQL_CONFIG --libs 2>/dev/null | filterLibraryOptions` + # -rdynamic should not be returned by mysql_config, but is on RHEL 6.6 + QT_LFLAGS_MYSQL_R=`$CFG_MYSQL_CONFIG --libs_r 2>/dev/null | filterLibraryOptions | sed "s/-rdynamic//"` + QT_LFLAGS_MYSQL=`$CFG_MYSQL_CONFIG --libs 2>/dev/null | filterLibraryOptions | sed "s/-rdynamic//"` QT_MYSQL_VERSION=`$CFG_MYSQL_CONFIG --version 2>/dev/null` QT_MYSQL_VERSION_MAJOR=`echo $QT_MYSQL_VERSION | cut -d . -f 1` fi diff --git a/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in index fc6bfcebcf..9c25feb43f 100644 --- a/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in +++ b/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in @@ -22,7 +22,9 @@ </Properties> <Dependencies> - <TargetDeviceFamily Name=\"Windows.Universal\" MinVersion=\"10.0.10586.0\" MaxVersionTested=\"10.0.10586.0\" />$${WINRT_MANIFEST.dependencies} + <TargetDeviceFamily Name=\"Windows.Universal\" + MinVersion=\"$${WINRT_MANIFEST.minVersion}\" + MaxVersionTested=\"$${WINRT_MANIFEST.maxVersionTested}\" />$${WINRT_MANIFEST.dependencies} </Dependencies> <Resources> diff --git a/mkspecs/features/qt_build_extra.prf b/mkspecs/features/qt_build_extra.prf index 378f5bbd7c..abdd7bc2b2 100644 --- a/mkspecs/features/qt_build_extra.prf +++ b/mkspecs/features/qt_build_extra.prf @@ -13,7 +13,7 @@ equals(TEMPLATE, subdirs): return() # It's likely that these extra flags will be wrong for host builds, # and the bootstrapped tools usually don't need them anyway. -host_build:force_bootstrap: return() +host_build:cross_compile: return() # The headersclean check needs defines and includes even for # header-only modules. diff --git a/mkspecs/features/qt_common.prf b/mkspecs/features/qt_common.prf index de9ba9dde9..c1809468af 100644 --- a/mkspecs/features/qt_common.prf +++ b/mkspecs/features/qt_common.prf @@ -44,9 +44,9 @@ contains(TEMPLATE, .*lib) { QMAKE_PRL_INSTALL_REPLACE += lib_replace } -# The remainder of this file must not apply to bootstrapped tools, +# The remainder of this file must not apply to host tools/libraries, # as the host compiler's version and capabilities are not checked. -host_build:force_bootstrap: return() +host_build:cross_compile: return() warnings_are_errors:warning_clean { # If the module declares that it has does its clean-up of warnings, enable -Werror. @@ -54,10 +54,10 @@ warnings_are_errors:warning_clean { # compiler. clang:!ios { # Apple clang 4.0-4.2,5.0-5.1,6.0-6.4 - # Regular clang 3.3-3.8 + # Regular clang 3.3-3.9 apple_ver = $${QT_APPLE_CLANG_MAJOR_VERSION}.$${QT_APPLE_CLANG_MINOR_VERSION} reg_ver = $${QT_CLANG_MAJOR_VERSION}.$${QT_CLANG_MINOR_VERSION} - contains(apple_ver, "4\\.[012]|5\\.[01]|6\\.[01234]")|contains(reg_ver, "3\\.[3-8]") { + contains(apple_ver, "4\\.[012]|5\\.[01]|6\\.[01234]")|contains(reg_ver, "3\\.[3-9]") { QMAKE_CXXFLAGS_WARN_ON += -Werror -Wno-error=\\$${LITERAL_HASH}warnings -Wno-error=deprecated-declarations $$WERROR } } else:intel_icc:linux { diff --git a/mkspecs/features/winrt/package_manifest.prf b/mkspecs/features/winrt/package_manifest.prf index 291ebec6e9..e17bda3c8e 100644 --- a/mkspecs/features/winrt/package_manifest.prf +++ b/mkspecs/features/winrt/package_manifest.prf @@ -31,6 +31,8 @@ # WINRT_MANIFEST.capabilities: Specifies capabilities to add to the capability list. # WINRT_MANIFEST.capabilities_device: Specifies device capabilities to add to the capability list. (location, webcam...) # WINRT_MANIFEST.dependencies: Specifies dependencies required by the package. +# WINRT_MANIFEST.minVersion: Specifies the minimum required Windows version to run the package. Defaults to %UCRTVersion% +# WINRT_MANIFEST.maxVersionTested: Specifies the maximum Windows version the package has been tested against. Defaults to WINRT_MANIFEST.minVersion # The manifest is generated for each build pass for normal apps, and only once for vcapps. # - Normal apps have their package root directory in the same place as the target (one for each build pass). @@ -91,6 +93,11 @@ isEmpty(WINRT_MANIFEST.background): WINRT_MANIFEST.background = green isEmpty(WINRT_MANIFEST.foreground): WINRT_MANIFEST.foreground = light isEmpty(WINRT_MANIFEST.default_language): WINRT_MANIFEST.default_language = en + *-msvc2015 { + isEmpty(WINRT_MANIFEST.minVersion): WINRT_MANIFEST.minVersion = $$(UCRTVersion) + isEmpty(WINRT_MANIFEST.minVersion): error("No UCRTVersion found in environment.")) + isEmpty(WINRT_MANIFEST.maxVersionTested): WINRT_MANIFEST.maxVersionTested = $$WINRT_MANIFEST.minVersion + } INDENT = "$$escape_expand(\\r\\n) " diff --git a/mkspecs/macx-ios-clang/ios_destinations.sh b/mkspecs/macx-ios-clang/ios_destinations.sh index ce6b238a65..b85f59ca30 100755 --- a/mkspecs/macx-ios-clang/ios_destinations.sh +++ b/mkspecs/macx-ios-clang/ios_destinations.sh @@ -33,7 +33,8 @@ ## ############################################################################# -booted_simulator=$(xcrun simctl list devices | grep -E "iPhone|iPad" | grep -v unavailable | grep Booted | perl -lne 'print $1 if /\((.*?)\)/') +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +booted_simulator=$($DIR/ios_devices.pl "iPhone|iPad" "Booted" "NOT unavailable" | tail -n 1) echo "IPHONESIMULATOR_DEVICES = $booted_simulator" xcodebuild test -scheme $1 -destination 'id=0' -destination-timeout 1 2>&1| sed -n 's/{ \(platform:.*\) }/\1/p' | while read destination; do diff --git a/mkspecs/macx-ios-clang/ios_devices.pl b/mkspecs/macx-ios-clang/ios_devices.pl new file mode 100755 index 0000000000..eb45d1dab9 --- /dev/null +++ b/mkspecs/macx-ios-clang/ios_devices.pl @@ -0,0 +1,50 @@ +#!/usr/bin/perl + +############################################################################# +## +## Copyright (C) 2016 The Qt Company Ltd. +## Contact: http://www.qt.io/licensing/ +## +## This file is the build configuration utility of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL21$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see http://www.qt.io/terms-conditions. For further +## information use the contact form at http://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 or version 3 as published by the Free +## Software Foundation and appearing in the file LICENSE.LGPLv21 and +## LICENSE.LGPLv3 included in the packaging of this file. Please review the +## following information to ensure the GNU Lesser General Public License +## requirements will be met: https://www.gnu.org/licenses/lgpl.html and +## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## As a special exception, The Qt Company gives you certain additional +## rights. These rights are described in The Qt Company LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## $QT_END_LICENSE$ +## +############################################################################# + +$output = `xcrun simctl list devices --json 2>&1`; +$output =~ s/\n//g; + +BLOCK: +foreach $block ($output =~ /{.*?}/g) { + foreach $filter (@ARGV) { + if ($filter =~ /^NOT\s(.*)/) { + $block =~ /$1/ && next BLOCK; + } else { + $block =~ /$filter/ || next BLOCK; + } + } + $block =~ /udid[:|\s|\"]+(.*)\"/; + print "$1\n"; +} diff --git a/mkspecs/macx-ios-clang/xcodebuild.mk b/mkspecs/macx-ios-clang/xcodebuild.mk index 1bd18430df..bf6b791368 100644 --- a/mkspecs/macx-ios-clang/xcodebuild.mk +++ b/mkspecs/macx-ios-clang/xcodebuild.mk @@ -56,11 +56,12 @@ iphonesimulator-install: ACTION = build release-%: CONFIGURATION = Release debug-%: CONFIGURATION = Debug +SPECDIR := $(dir $(lastword $(MAKEFILE_LIST))) + # Test and build (device) destinations ifneq ($(filter check%,$(MAKECMDGOALS)),) ifeq ($(DEVICES),) $(info Enumerating test destinations (you may override this by setting DEVICES explicitly), please wait...) - SPECDIR := $(dir $(lastword $(MAKEFILE_LIST))) DESTINATIONS_INCLUDE = /tmp/ios_destinations.mk $(shell $(SPECDIR)/ios_destinations.sh $(TARGET) > $(DESTINATIONS_INCLUDE)) include $(DESTINATIONS_INCLUDE) @@ -71,7 +72,7 @@ endif %-iphoneos: DEVICES = $(IPHONEOS_DEVICES) IPHONEOS_GENERIC_DESTINATION := "generic/platform=iOS" -IPHONESIMULATOR_GENERIC_DESTINATION := "id=$(shell xcrun simctl list devices | grep -E 'iPhone|iPad' | grep -v unavailable | perl -lne 'print $$1 if /\((.*?)\)/' | tail -n 1)" +IPHONESIMULATOR_GENERIC_DESTINATION := "id=$(shell $(SPECDIR)/ios_devices.pl "iPhone|iPad" "NOT unavailable" | tail -n 1)" DESTINATION = $(if $(DESTINATION_ID),"id=$(DESTINATION_ID)",$(value $(call toupper,$(call basesdk,$(SDK)))_GENERIC_DESTINATION)) diff --git a/mkspecs/macx-xcode/default.xcscheme b/mkspecs/macx-xcode/default.xcscheme index ab2f6a8ab7..6beb0d8280 100644 --- a/mkspecs/macx-xcode/default.xcscheme +++ b/mkspecs/macx-xcode/default.xcscheme @@ -62,7 +62,7 @@ useCustomWorkingDirectory = "NO" buildConfiguration = "Debug" ignoresPersistentStateOnLaunch = "NO" - debugDocumentVersioning = "YES" + debugDocumentVersioning = "NO" allowLocationSimulation = "YES"> <BuildableProductRunnable> <BuildableReference @@ -88,7 +88,7 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" buildConfiguration = "Release" - debugDocumentVersioning = "YES"> + debugDocumentVersioning = "NO"> <BuildableProductRunnable> <BuildableReference BuildableIdentifier = "primary" diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index ea400c5faf..7386af881e 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -2693,6 +2693,13 @@ \row \li version \li The version number of the package. Defaults to \c{1.0.0.0}. + \row + \li minVersion + \li The minimum required Windows version to run the package. Defaults to the environment variable \c UCRTVersion. + \row + \li maxVersionTested + \li The maximum Windows version the package has been tested against. Defaults to \c WINRT_MANIFEST.minVersion + \endtable You can use any combination of those values. diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index 0c64db4d48..fbd14e2d5d 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -576,7 +576,7 @@ void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data) QString comment; QString mainPattern; - const QString preferredLanguage = QLocale::system().name(); + const QString preferredLanguage = QLocale().name(); for (QStringList::const_reverse_iterator it = mimeFiles.crbegin(), end = mimeFiles.crend(); it != end; ++it) { // global first, then local. QFile qfile(*it); diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index e3b01bbb89..980e8c1e5e 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -232,15 +232,15 @@ QString QMimeType::name() const /*! Returns the description of the MIME type to be displayed on user interfaces. - The system language (QLocale::system().name()) is used to select the appropriate translation. + The default language (QLocale().name()) is used to select the appropriate translation. */ QString QMimeType::comment() const { QMimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d); QStringList languageList; - languageList << QLocale::system().name(); - languageList << QLocale::system().uiLanguages(); + languageList << QLocale().name(); + languageList << QLocale().uiLanguages(); Q_FOREACH (const QString &language, languageList) { const QString lang = language == QLatin1String("C") ? QLatin1String("en_US") : language; const QString comm = d->localeComments.value(lang); diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index e1e5367766..3531be412e 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -835,8 +835,11 @@ QPixmap QIcon::pixmap(QWindow *window, const QSize &size, Mode mode, State state qreal devicePixelRatio = qt_effective_device_pixel_ratio(window); // Handle the simple normal-dpi case: - if (!(devicePixelRatio > 1.0)) - return d->engine->pixmap(size, mode, state); + if (!(devicePixelRatio > 1.0)) { + QPixmap pixmap = d->engine->pixmap(size, mode, state); + pixmap.setDevicePixelRatio(1.0); + return pixmap; + } // Try get a pixmap that is big enough to be displayed at device pixel resolution. QPixmap pixmap = d->engine->pixmap(size * devicePixelRatio, mode, state); diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 1934342f96..ea71e34e4b 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -405,7 +405,7 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni static const struct { int key; - const char* name; + const char name[25]; } keyname[] = { //: This and all following "incomprehensible" strings in QShortcut context //: are key names. Please use the localized names appearing on actual @@ -687,8 +687,8 @@ static const struct { { Qt::Key_TouchpadOn, QT_TRANSLATE_NOOP("QShortcut", "Touchpad On") }, { Qt::Key_TouchpadOff, QT_TRANSLATE_NOOP("QShortcut", "Touchpad Off") }, - { 0, 0 } }; +static Q_CONSTEXPR int numKeyNames = sizeof keyname / sizeof *keyname; /*! \enum QKeySequence::StandardKey @@ -1172,7 +1172,7 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence for (int tran = 0; tran < 2; ++tran) { if (!nativeText) ++tran; - for (int i = 0; keyname[i].name; ++i) { + for (int i = 0; i < numKeyNames; ++i) { QString keyName(tran == 0 ? QCoreApplication::translate("QShortcut", keyname[i].name) : QString::fromLatin1(keyname[i].name)); @@ -1311,7 +1311,7 @@ QString QKeySequencePrivate::keyName(int key, QKeySequence::SequenceFormat forma #if defined(Q_OS_MACX) NonSymbol: #endif - while (keyname[i].name) { + while (i < numKeyNames) { if (key == keyname[i].key) { p = nativeText ? QCoreApplication::translate("QShortcut", keyname[i].name) : QString::fromLatin1(keyname[i].name); @@ -1323,7 +1323,7 @@ NonSymbol: // fall back on the unicode representation of it... // Or else characters like Qt::Key_aring may not get displayed // (Really depends on you locale) - if (!keyname[i].name) { + if (i >= numKeyNames) { if (!QChar::requiresSurrogates(key)) { p = QChar(ushort(key)).toUpper(); } else { diff --git a/src/gui/kernel/qoffscreensurface.cpp b/src/gui/kernel/qoffscreensurface.cpp index 1a12ea4d32..056cc19f69 100644 --- a/src/gui/kernel/qoffscreensurface.cpp +++ b/src/gui/kernel/qoffscreensurface.cpp @@ -177,6 +177,7 @@ void QOffscreenSurface::create() if (QThread::currentThread() != qGuiApp->thread()) qWarning("Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures."); d->offscreenWindow = new QWindow(d->screen); + d->offscreenWindow->setObjectName(QLatin1String("QOffscreenSurface")); // Remove this window from the global list since we do not want it to be destroyed when closing the app. // The QOffscreenSurface has to be usable even after exiting the event loop. QGuiApplicationPrivate::window_list.removeOne(d->offscreenWindow); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 7f84706b6f..bcd29b6fe1 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -204,6 +204,8 @@ QWindow::~QWindow() { destroy(); QGuiApplicationPrivate::window_list.removeAll(this); + if (!QGuiApplicationPrivate::is_app_closing) + QGuiApplicationPrivate::instance()->modalWindowList.removeOne(this); } void QWindowPrivate::init() @@ -2158,6 +2160,9 @@ void QWindowPrivate::deliverUpdateRequest() */ void QWindow::requestUpdate() { + Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread(), + "QWindow", "Updates can only be scheduled from the GUI (main) thread"); + Q_D(QWindow); if (d->updateRequestPending || !d->platformWindow) return; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index a0f7155c67..ac22c7fc00 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -5754,9 +5754,9 @@ static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int dg = gamma[dg]; db = gamma[db]; - int nr = qt_div_255((sr - dr) * mr) + dr; - int ng = qt_div_255((sg - dg) * mg) + dg; - int nb = qt_div_255((sb - db) * mb) + db; + int nr = qt_div_255(sr * mr + dr * (255 - mr)); + int ng = qt_div_255(sg * mg + dg * (255 - mg)); + int nb = qt_div_255(sb * mb + db * (255 - mb)); nr = invgamma[nr]; ng = invgamma[ng]; @@ -5781,9 +5781,9 @@ static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, in int alpha = coverage; int ialpha = 255 - alpha; - int nr = (sr * alpha + ialpha * dr) / 255; - int ng = (sg * alpha + ialpha * dg) / 255; - int nb = (sb * alpha + ialpha * db) / 255; + int nr = qt_div_255(sr * alpha + dr * ialpha); + int ng = qt_div_255(sg * alpha + dg * ialpha); + int nb = qt_div_255(sb * alpha + db * ialpha); nr = invgamma[nr]; ng = invgamma[ng]; diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index ff98d186c5..d636eabe3f 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -705,6 +705,7 @@ static Q_ALWAYS_INLINE uint BYTE_MUL_RGB16_32(uint x, uint a) { return t; } +// qt_div_255 is a fast rounded division by 255 using an approximation that is accurate for all positive 16-bit integers static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; } static Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; } diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 5e8aac82b8..fa49b25073 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -1046,46 +1046,45 @@ QByteArray QFontEngine::getSfntTable(uint tag) const return table; } -void QFontEngine::clearGlyphCache(const void *key) +void QFontEngine::clearGlyphCache(const void *context) { - for (QLinkedList<GlyphCacheEntry>::iterator it = m_glyphCaches.begin(), end = m_glyphCaches.end(); it != end; ) { - if (it->context == key) - it = m_glyphCaches.erase(it); - else - ++it; - } + m_glyphCaches.remove(context); } -void QFontEngine::setGlyphCache(const void *key, QFontEngineGlyphCache *data) +void QFontEngine::setGlyphCache(const void *context, QFontEngineGlyphCache *cache) { - Q_ASSERT(data); + Q_ASSERT(cache); - GlyphCacheEntry entry; - entry.context = key; - entry.cache = data; - if (m_glyphCaches.contains(entry)) - return; + GlyphCaches &caches = m_glyphCaches[context]; + for (GlyphCaches::const_iterator it = caches.constBegin(), end = caches.constEnd(); it != end; ++it) { + if (cache == it->cache.data()) + return; + } - // Limit the glyph caches to 4. This covers all 90 degree rotations and limits - // memory use when there is continuous or random rotation - if (m_glyphCaches.size() == 4) - m_glyphCaches.removeLast(); + // Limit the glyph caches to 4 per context. This covers all 90 degree rotations, + // and limits memory use when there is continuous or random rotation + if (caches.size() == 4) + caches.removeLast(); - m_glyphCaches.push_front(entry); + GlyphCacheEntry entry; + entry.cache = cache; + caches.push_front(entry); } -QFontEngineGlyphCache *QFontEngine::glyphCache(const void *key, GlyphFormat format, const QTransform &transform) const +QFontEngineGlyphCache *QFontEngine::glyphCache(const void *context, GlyphFormat format, const QTransform &transform) const { - for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(), end = m_glyphCaches.constEnd(); it != end; ++it) { - QFontEngineGlyphCache *c = it->cache.data(); - if (key == it->context - && format == c->glyphFormat() - && qtransform_equals_no_translate(c->m_transform, transform)) { - return c; - } + const QHash<const void*, GlyphCaches>::const_iterator caches = m_glyphCaches.constFind(context); + if (caches == m_glyphCaches.cend()) + return Q_NULLPTR; + + for (GlyphCaches::const_iterator it = caches->begin(), end = caches->end(); it != end; ++it) { + QFontEngineGlyphCache *cache = it->cache.data(); + if (format == cache->glyphFormat() && qtransform_equals_no_translate(cache->m_transform, transform)) + return cache; } - return 0; + + return Q_NULLPTR; } static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs) @@ -1565,12 +1564,11 @@ QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs, bool round) QFontEngine::GlyphCacheEntry::GlyphCacheEntry() - : context(0) { } QFontEngine::GlyphCacheEntry::GlyphCacheEntry(const GlyphCacheEntry &o) - : context(o.context), cache(o.cache) + : cache(o.cache) { } @@ -1580,7 +1578,6 @@ QFontEngine::GlyphCacheEntry::~GlyphCacheEntry() QFontEngine::GlyphCacheEntry &QFontEngine::GlyphCacheEntry::operator=(const GlyphCacheEntry &o) { - context = o.context; cache = o.cache; return *this; } diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 7ddc5c0c32..39cf826ee2 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -316,12 +316,11 @@ private: GlyphCacheEntry &operator=(const GlyphCacheEntry &); - const void *context; QExplicitlySharedDataPointer<QFontEngineGlyphCache> cache; - bool operator==(const GlyphCacheEntry &other) const { return context == other.context && cache == other.cache; } + bool operator==(const GlyphCacheEntry &other) const { return cache == other.cache; } }; - - mutable QLinkedList<GlyphCacheEntry> m_glyphCaches; + typedef QLinkedList<GlyphCacheEntry> GlyphCaches; + mutable QHash<const void *, GlyphCaches> m_glyphCaches; private: QVariant m_userData; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 3edf652f35..6cccf417c7 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -1309,7 +1309,7 @@ QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags op //do not include the character given in the position. if (options & FindBackward) { --pos ; - if (pos < subString.size()) + if (pos < 0) return QTextCursor(); } diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 9c1e7a6a49..3d665270fd 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -103,12 +103,12 @@ To close the socket, call disconnectFromHost(). QAbstractSocket enters QAbstractSocket::ClosingState. After all pending data has been written to the socket, QAbstractSocket actually closes the socket, enters - QAbstractSocket::ClosedState, and emits disconnected(). If you want to - abort a connection immediately, discarding all pending data, call abort() - instead. If the remote host closes the connection, QAbstractSocket will - emit error(QAbstractSocket::RemoteHostClosedError), during which the socket - state will still be ConnectedState, and then the disconnected() signal - will be emitted. + QAbstractSocket::UnconnectedState, and emits disconnected(). If you want + to abort a connection immediately, discarding all pending data, call + abort() instead. If the remote host closes the connection, + QAbstractSocket will emit error(QAbstractSocket::RemoteHostClosedError), + during which the socket state will still be ConnectedState, and then the + disconnected() signal will be emitted. The port and address of the connected peer is fetched by calling peerPort() and peerAddress(). peerName() returns the host name of diff --git a/src/platformsupport/cglconvenience/cglconvenience.mm b/src/platformsupport/cglconvenience/cglconvenience.mm index 6b0a91e13f..fb609ae485 100644 --- a/src/platformsupport/cglconvenience/cglconvenience.mm +++ b/src/platformsupport/cglconvenience/cglconvenience.mm @@ -81,8 +81,11 @@ void *qcgl_createNSOpenGLPixelFormat(const QSurfaceFormat &format) QVector<NSOpenGLPixelFormatAttribute> attrs; - if (format.swapBehavior() != QSurfaceFormat::SingleBuffer) + if (format.swapBehavior() == QSurfaceFormat::DoubleBuffer + || format.swapBehavior() == QSurfaceFormat::DefaultSwapBehavior) attrs.append(NSOpenGLPFADoubleBuffer); + else if (format.swapBehavior() == QSurfaceFormat::TripleBuffer) + attrs.append(NSOpenGLPFATripleBuffer); #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 13b64a556c..1b1034817e 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -123,6 +123,9 @@ void QNetworkManagerEngine::setupConfigurations() // Get active connections. foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { + if (activeConnectionsList.contains(acPath.path())) + continue; + QNetworkManagerConnectionActive *activeConnection = new QNetworkManagerConnectionActive(acPath.path(),this); activeConnectionsList.insert(acPath.path(), activeConnection); @@ -135,14 +138,6 @@ void QNetworkManagerEngine::setupConfigurations() connectionInterfaces.insert(activeConnection->connection().path(),device.networkInterface()); } } - - // Get current list of access points. - foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { - locker.unlock(); - deviceAdded(devicePath); //add all accesspoints - locker.relock(); - } - // Get connections. foreach (const QDBusObjectPath &settingsPath, systemSettings->listConnections()) { locker.unlock(); @@ -251,11 +246,6 @@ void QNetworkManagerEngine::requestUpdate() QMetaObject::invokeMethod(this, "updateCompleted", Qt::QueuedConnection); } -void QNetworkManagerEngine::scanFinished() -{ - QMetaObject::invokeMethod(this, "updateCompleted", Qt::QueuedConnection); -} - void QNetworkManagerEngine::interfacePropertiesChanged(const QMap<QString, QVariant> &properties) { QMutexLocker locker(&mutex); @@ -397,57 +387,6 @@ void QNetworkManagerEngine::deviceConnectionsChanged(const QStringList &connecti } } -void QNetworkManagerEngine::deviceAdded(const QDBusObjectPath &path) -{ - QNetworkManagerInterfaceDevice *iDevice; - iDevice = new QNetworkManagerInterfaceDevice(path.path(),this); - connect(iDevice,SIGNAL(connectionsChanged(QStringList)), - this,SLOT(deviceConnectionsChanged(QStringList))); - - interfaceDevices.insert(path.path(),iDevice); - if (iDevice->deviceType() == DEVICE_TYPE_WIFI) { - QNetworkManagerInterfaceDeviceWireless *wirelessDevice = - new QNetworkManagerInterfaceDeviceWireless(iDevice->path(),this); - - connect(wirelessDevice, SIGNAL(accessPointAdded(QString)), - this, SLOT(newAccessPoint(QString))); - connect(wirelessDevice, SIGNAL(accessPointRemoved(QString)), - this, SLOT(removeAccessPoint(QString))); - connect(wirelessDevice,SIGNAL(scanDone()),this,SLOT(scanFinished())); - wirelessDevice->setConnections(); - - wirelessDevices.insert(path.path(), wirelessDevice); - } - - if (iDevice->deviceType() == DEVICE_TYPE_ETHERNET) { - QNetworkManagerInterfaceDeviceWired *wiredDevice = - new QNetworkManagerInterfaceDeviceWired(iDevice->path(),this); - connect(wiredDevice,SIGNAL(carrierChanged(bool)),this,SLOT(wiredCarrierChanged(bool))); - wiredDevices.insert(iDevice->path(), wiredDevice); - } -} - -void QNetworkManagerEngine::deviceRemoved(const QDBusObjectPath &path) -{ - QMutexLocker locker(&mutex); - - if (interfaceDevices.contains(path.path())) { - locker.unlock(); - delete interfaceDevices.take(path.path()); - locker.relock(); - } - if (wirelessDevices.contains(path.path())) { - locker.unlock(); - delete wirelessDevices.take(path.path()); - locker.relock(); - } - if (wiredDevices.contains(path.path())) { - locker.unlock(); - delete wiredDevices.take(path.path()); - locker.relock(); - } -} - void QNetworkManagerEngine::wiredCarrierChanged(bool carrier) { QNetworkManagerInterfaceDeviceWired *deviceWired = qobject_cast<QNetworkManagerInterfaceDeviceWired *>(sender()); @@ -538,7 +477,7 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, if (i.value()->deviceType() == deviceType) { QNetworkManagerInterfaceDeviceWired *wiredDevice = wiredDevices.value(i.value()->path()); - if (wiredDevice->carrier()) { + if (wiredDevice && wiredDevice->carrier()) { cpPriv->state |= QNetworkConfiguration::Discovered; } } @@ -596,15 +535,10 @@ void QNetworkManagerEngine::removeConnection(const QString &path) emit configurationRemoved(ptr); locker.relock(); } + // add base AP back into configurations - QMapIterator<QString, QString> i(configuredAccessPoints); - while (i.hasNext()) { - i.next(); - if (i.value() == path) { - configuredAccessPoints.remove(i.key()); - newAccessPoint(i.key()); - } - } + + // removed along with all AP props code... } void QNetworkManagerEngine::updateConnection() @@ -678,114 +612,6 @@ void QNetworkManagerEngine::activationFinished(QDBusPendingCallWatcher *watcher) } } -void QNetworkManagerEngine::newAccessPoint(const QString &path) -{ - QMutexLocker locker(&mutex); - QNetworkManagerInterfaceAccessPoint *accessPoint = - new QNetworkManagerInterfaceAccessPoint(path,this); - - bool okToAdd = true; - for (int i = 0; i < accessPoints.count(); ++i) { - if (accessPoints.at(i)->path() == path) { - okToAdd = false; - } - } - if (okToAdd) { - accessPoints.append(accessPoint); - } - // Check if configuration exists for connection. - if (!accessPoint->ssid().isEmpty()) { - - for (int i = 0; i < connections.count(); ++i) { - QNetworkManagerSettingsConnection *connection = connections.at(i); - const QString settingsPath = connection->path(); - - if (accessPoint->ssid() == connection->getSsid()) { - if (!configuredAccessPoints.contains(path)) { - configuredAccessPoints.insert(path,settingsPath); - } - - QNetworkConfigurationPrivatePointer ptr = - accessPointConfigurations.value(settingsPath); - ptr->mutex.lock(); - QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined; - ptr->state = (flag | QNetworkConfiguration::Discovered); - - if (isConnectionActive(settingsPath)) - ptr->state = (flag | QNetworkConfiguration::Active); - ptr->mutex.unlock(); - - locker.unlock(); - emit configurationChanged(ptr); - return; - } - } - } - - // New access point. - QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate); - - ptr->name = accessPoint->ssid(); - ptr->isValid = true; - ptr->id = path; - ptr->type = QNetworkConfiguration::InternetAccessPoint; - ptr->purpose = QNetworkConfiguration::PublicPurpose; - ptr->state = QNetworkConfiguration::Undefined; - ptr->bearerType = QNetworkConfiguration::BearerWLAN; - - accessPointConfigurations.insert(ptr->id, ptr); - - locker.unlock(); - emit configurationAdded(ptr); -} - -void QNetworkManagerEngine::removeAccessPoint(const QString &path) -{ - QMutexLocker locker(&mutex); - for (int i = 0; i < accessPoints.count(); ++i) { - QNetworkManagerInterfaceAccessPoint *accessPoint = accessPoints.at(i); - if (accessPoint->path() == path) { - accessPoints.removeOne(accessPoint); - - if (configuredAccessPoints.contains(accessPoint->path())) { - // find connection and change state to Defined - configuredAccessPoints.remove(accessPoint->path()); - - for (int i = 0; i < connections.count(); ++i) { - QNetworkManagerSettingsConnection *connection = connections.at(i); - - if (accessPoint->ssid() == connection->getSsid()) {//might not have bssid yet - const QString settingsPath = connection->path(); - const QString connectionId = settingsPath; - - QNetworkConfigurationPrivatePointer ptr = - accessPointConfigurations.value(connectionId); - ptr->mutex.lock(); - ptr->state = QNetworkConfiguration::Defined; - ptr->mutex.unlock(); - - locker.unlock(); - emit configurationChanged(ptr); - locker.relock(); - break; - } - } - } else { - QNetworkConfigurationPrivatePointer ptr = - accessPointConfigurations.take(path); - - if (ptr) { - locker.unlock(); - emit configurationRemoved(ptr); - locker.relock(); - } - } - delete accessPoint; - break; - } - } -} - QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QString &settingsPath, const QNmSettingsMap &map) { @@ -808,7 +634,7 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri QNetworkManagerInterfaceDevice device(devicePath.path(),this); if (device.deviceType() == DEVICE_TYPE_ETHERNET) { QNetworkManagerInterfaceDeviceWired *wiredDevice = wiredDevices.value(device.path()); - if (wiredDevice->carrier()) { + if (wiredDevice && wiredDevice->carrier()) { cpPriv->state |= QNetworkConfiguration::Discovered; break; } @@ -1078,10 +904,6 @@ void QNetworkManagerEngine::nmRegistered(const QString &) managerInterface = new QNetworkManagerInterface(this); systemSettings = new QNetworkManagerSettings(NM_DBUS_SERVICE, this); - connect(managerInterface, SIGNAL(deviceAdded(QDBusObjectPath)), - this, SLOT(deviceAdded(QDBusObjectPath))); - connect(managerInterface, SIGNAL(deviceRemoved(QDBusObjectPath)), - this, SLOT(deviceRemoved(QDBusObjectPath))); connect(managerInterface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)), this, SLOT(activationFinished(QDBusPendingCallWatcher*))); connect(managerInterface, SIGNAL(propertiesChanged(QMap<QString,QVariant>)), diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h index 1f578890dc..b859318a5b 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h @@ -93,19 +93,12 @@ private Q_SLOTS: void interfacePropertiesChanged(const QMap<QString, QVariant> &properties); void activeConnectionPropertiesChanged(const QMap<QString, QVariant> &properties); - void deviceAdded(const QDBusObjectPath &path); - void deviceRemoved(const QDBusObjectPath &path); - void newConnection(const QDBusObjectPath &path, QNetworkManagerSettings *settings = 0); void removeConnection(const QString &path); void updateConnection(); void activationFinished(QDBusPendingCallWatcher *watcher); void deviceConnectionsChanged(const QStringList &activeConnectionsList); - void newAccessPoint(const QString &path); - void removeAccessPoint(const QString &path); - void scanFinished(); - void wiredCarrierChanged(bool); void nmRegistered(const QString &serviceName = QString()); diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp index d550887ba6..7506b768f2 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -95,6 +95,21 @@ QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent) QNetworkManagerInterface::~QNetworkManagerInterface() { + QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String(NM_DBUS_INTERFACE), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap<QString,QVariant>))); + QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String(NM_DBUS_INTERFACE), + QLatin1String("DeviceAdded"), + this,SIGNAL(deviceAdded(QDBusObjectPath))); + QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String(NM_DBUS_INTERFACE), + QLatin1String("DeviceRemoved"), + this,SIGNAL(deviceRemoved(QDBusObjectPath))); } bool QNetworkManagerInterface::setConnections() @@ -235,28 +250,6 @@ QNetworkManagerInterfaceAccessPoint::QNetworkManagerInterfaceAccessPoint(const Q NM_DBUS_INTERFACE_ACCESS_POINT, QDBusConnection::systemBus(),parent) { - if (!isValid()) { - return; - } - PropertiesDBusInterface *accessPointPropertiesInterface = new PropertiesDBusInterface(QLatin1String(NM_DBUS_SERVICE), - dbusPathName, - DBUS_PROPERTIES_INTERFACE, - QDBusConnection::systemBus()); - - QList<QVariant> argumentList; - argumentList << QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT); - QDBusPendingReply<QVariantMap> propsReply - = accessPointPropertiesInterface->callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), - argumentList); - if (!propsReply.isError()) { - propertyMap = propsReply.value(); - } - - QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), - dbusPathName, - QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT), - QLatin1String("PropertiesChanged"), - this,SLOT(propertiesSwap(QMap<QString,QVariant>))); } QNetworkManagerInterfaceAccessPoint::~QNetworkManagerInterfaceAccessPoint() @@ -369,6 +362,11 @@ QNetworkManagerInterfaceDevice::QNetworkManagerInterfaceDevice(const QString &de QNetworkManagerInterfaceDevice::~QNetworkManagerInterfaceDevice() { + QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE), + path(), + QLatin1String(NM_DBUS_INTERFACE_DEVICE), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap<QString,QVariant>))); } QString QNetworkManagerInterfaceDevice::udi() const @@ -468,6 +466,11 @@ QNetworkManagerInterfaceDeviceWired::QNetworkManagerInterfaceDeviceWired(const Q QNetworkManagerInterfaceDeviceWired::~QNetworkManagerInterfaceDeviceWired() { + QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE), + path(), + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap<QString,QVariant>))); } QString QNetworkManagerInterfaceDeviceWired::hwAddress() const @@ -557,77 +560,20 @@ QNetworkManagerInterfaceDeviceWireless::QNetworkManagerInterfaceDeviceWireless(c QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), QLatin1String("PropertiesChanged"), this,SLOT(propertiesSwap(QMap<QString,QVariant>))); - - QDBusPendingReply<QList<QDBusObjectPath> > reply - = asyncCall(QLatin1String("GetAccessPoints")); - - QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(reply); - connect(callWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), - this, SLOT(accessPointsFinished(QDBusPendingCallWatcher*))); } QNetworkManagerInterfaceDeviceWireless::~QNetworkManagerInterfaceDeviceWireless() { -} - -void QNetworkManagerInterfaceDeviceWireless::slotAccessPointAdded(QDBusObjectPath path) -{ - if (path.path().length() > 2) - Q_EMIT accessPointAdded(path.path()); -} - -void QNetworkManagerInterfaceDeviceWireless::slotAccessPointRemoved(QDBusObjectPath path) -{ - if (path.path().length() > 2) - Q_EMIT accessPointRemoved(path.path()); + QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE), + path(), + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap<QString,QVariant>))); } bool QNetworkManagerInterfaceDeviceWireless::setConnections() { - if (!isValid()) - return false; - - QDBusConnection dbusConnection = QDBusConnection::systemBus(); - bool allOk = true; - - if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), - interfacePath, - QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), - QLatin1String("AccessPointAdded"), - this, SLOT(slotAccessPointAdded(QDBusObjectPath)))) { - allOk = false; - } - - - if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), - interfacePath, - QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), - QLatin1String("AccessPointRemoved"), - this, SLOT(slotAccessPointRemoved(QDBusObjectPath)))) { - allOk = false; - } - - if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), - interfacePath, - QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), - QLatin1String("ScanDone"), - this, SLOT(scanIsDone()))) { - allOk = false; - } - return allOk; -} - -void QNetworkManagerInterfaceDeviceWireless::accessPointsFinished(QDBusPendingCallWatcher *watcher) -{ - QDBusPendingReply<QList<QDBusObjectPath> > reply(*watcher); - watcher->deleteLater(); - if (!reply.isError()) { - accessPointsList = reply.value(); - } - - for (int i = 0; i < accessPointsList.size(); i++) { - Q_EMIT accessPointAdded(accessPointsList.at(i).path()); - } + return true; } QList <QDBusObjectPath> QNetworkManagerInterfaceDeviceWireless::getAccessPoints() @@ -676,11 +622,6 @@ quint32 QNetworkManagerInterfaceDeviceWireless::wirelessCapabilities() const return 0; } -void QNetworkManagerInterfaceDeviceWireless::scanIsDone() -{ - Q_EMIT scanDone(); -} - void QNetworkManagerInterfaceDeviceWireless::requestScan() { asyncCall(QLatin1String("RequestScan")); @@ -729,6 +670,12 @@ QNetworkManagerInterfaceDeviceModem::QNetworkManagerInterfaceDeviceModem(const Q QNetworkManagerInterfaceDeviceModem::~QNetworkManagerInterfaceDeviceModem() { + QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE), + path(), + QLatin1String(NM_DBUS_PATH_SETTINGS), + QLatin1String(NM_DBUS_IFACE_SETTINGS), + QLatin1String("NewConnection"), + this, SIGNAL(newConnection(QDBusObjectPath))); } QNetworkManagerInterfaceDeviceModem::ModemCapabilities QNetworkManagerInterfaceDeviceModem::modemCapabilities() const @@ -833,6 +780,16 @@ QNetworkManagerSettingsConnection::QNetworkManagerSettingsConnection(const QStri QNetworkManagerSettingsConnection::~QNetworkManagerSettingsConnection() { + QDBusConnection::systemBus().disconnect(service(), + path(), + QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION), + QLatin1String("Updated"), + this, SIGNAL(updated())); + QDBusConnection::systemBus().disconnect(service(), + path(), + QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION), + QLatin1String("Removed"), + this, SIGNAL(slotSettingsRemoved())); } bool QNetworkManagerSettingsConnection::setConnections() @@ -989,6 +946,11 @@ QNetworkManagerConnectionActive::QNetworkManagerConnectionActive(const QString & QNetworkManagerConnectionActive::~QNetworkManagerConnectionActive() { + QDBusConnection::systemBus().disconnect(QLatin1String(NM_DBUS_SERVICE), + path(), + QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap<QString,QVariant>))); } QDBusObjectPath QNetworkManagerConnectionActive::connection() const diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index 7956705789..4b810caf4a 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -322,7 +322,6 @@ public: QObject *parent = 0); ~QNetworkManagerInterfaceDeviceWireless(); - QDBusObjectPath path() const; QList <QDBusObjectPath> getAccessPoints(); QString hwAddress() const; @@ -335,21 +334,11 @@ public: void requestScan(); Q_SIGNALS: void propertiesChanged(QMap<QString,QVariant>); - void accessPointAdded(const QString &); - void accessPointRemoved(const QString &); - void scanDone(); void propertiesReady(); - void accessPointsReady(); private Q_SLOTS: - void scanIsDone(); void propertiesSwap(QMap<QString,QVariant>); - void slotAccessPointAdded(QDBusObjectPath); - void slotAccessPointRemoved(QDBusObjectPath); - - void accessPointsFinished(QDBusPendingCallWatcher *watcher); - private: QVariantMap propertyMap; QList <QDBusObjectPath> accessPointsList; diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 0f9b8b900d..b77ca07141 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -305,8 +305,16 @@ void QCocoaGLContext::updateSurfaceFormat() m_format.setSamples(samples); int doubleBuffered = -1; + int tripleBuffered = -1; [pixelFormat getValues:&doubleBuffered forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0]; - m_format.setSwapBehavior(doubleBuffered == 1 ? QSurfaceFormat::DoubleBuffer : QSurfaceFormat::SingleBuffer); + [pixelFormat getValues:&tripleBuffered forAttribute:NSOpenGLPFATripleBuffer forVirtualScreen:0]; + + if (tripleBuffered == 1) + m_format.setSwapBehavior(QSurfaceFormat::TripleBuffer); + else if (doubleBuffered == 1) + m_format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + else + m_format.setSwapBehavior(QSurfaceFormat::SingleBuffer); int steroBuffers = -1; [pixelFormat getValues:&steroBuffers forAttribute:NSOpenGLPFAStereo forVirtualScreen:0]; diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 0cf505930f..4bef968de1 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -908,7 +908,7 @@ UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()]; if (!uifont) return [NSDictionary dictionary]; - return [NSDictionary dictionaryWithObject:uifont forKey:UITextInputTextFontKey]; + return [NSDictionary dictionaryWithObject:uifont forKey:NSFontAttributeName]; } - (NSDictionary *)markedTextStyle diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 6e8df340df..94bb71e429 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -1044,12 +1044,15 @@ void QWindowsNativeFileDialogBase::setDirectory(const QUrl &directory) QString QWindowsNativeFileDialogBase::directory() const { + QString result; #ifndef Q_OS_WINCE IShellItem *item = 0; - if (m_fileDialog && SUCCEEDED(m_fileDialog->GetFolder(&item)) && item) - return QWindowsNativeFileDialogBase::itemPath(item); + if (m_fileDialog && SUCCEEDED(m_fileDialog->GetFolder(&item)) && item) { + result = QWindowsNativeFileDialogBase::itemPath(item); + item->Release(); + } #endif - return QString(); + return result; } void QWindowsNativeFileDialogBase::doExec(HWND owner) @@ -1514,8 +1517,10 @@ QList<QUrl> QWindowsNativeSaveFileDialog::selectedFiles() const QList<QUrl> result; IShellItem *item = 0; const HRESULT hr = fileDialog()->GetCurrentSelection(&item); - if (SUCCEEDED(hr) && item) + if (SUCCEEDED(hr) && item) { result.push_back(QUrl::fromLocalFile(QWindowsNativeSaveFileDialog::itemPath(item))); + item->Release(); + } return result; } diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.cpp b/src/plugins/platforms/winrt/qwinrtclipboard.cpp index c385018239..14443f380c 100644 --- a/src/plugins/platforms/winrt/qwinrtclipboard.cpp +++ b/src/plugins/platforms/winrt/qwinrtclipboard.cpp @@ -56,6 +56,7 @@ typedef IEventHandler<IInspectable *> ContentChangedHandler; QT_BEGIN_NAMESPACE QWinRTClipboard::QWinRTClipboard() + : m_mimeData(Q_NULLPTR) { #ifndef Q_OS_WINPHONE QEventDispatcherWinRT::runOnXamlThread([this]() { @@ -100,9 +101,16 @@ QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode) const wchar_t *textStr = result.GetRawBuffer(&size); QString text = QString::fromWCharArray(textStr, size); text.replace(QStringLiteral("\r\n"), QStringLiteral("\n")); - m_mimeData.setText(text); - return &m_mimeData; + if (m_mimeData) { + if (m_mimeData->text() == text) + return m_mimeData; + delete m_mimeData; + } + m_mimeData = new QMimeData(); + m_mimeData->setText(text); + + return m_mimeData; #else // Q_OS_WINPHONE return QPlatformClipboard::mimeData(mode); #endif // Q_OS_WINPHONE @@ -143,6 +151,12 @@ void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) return; #ifndef Q_OS_WINPHONE + const bool newData = !m_mimeData || m_mimeData != data; + if (newData) { + if (m_mimeData) + delete m_mimeData; + m_mimeData = data; + } const QString text = data ? data->text() : QString(); HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, text]() { HRESULT hr; @@ -161,7 +175,6 @@ void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) return S_OK; }); RETURN_VOID_IF_FAILED("Could not set clipboard text."); - emitChanged(mode); #else // Q_OS_WINPHONE QPlatformClipboard::setMimeData(data, mode); #endif // Q_OS_WINPHONE diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.h b/src/plugins/platforms/winrt/qwinrtclipboard.h index 1fb10bdfc0..fc3d50ce59 100644 --- a/src/plugins/platforms/winrt/qwinrtclipboard.h +++ b/src/plugins/platforms/winrt/qwinrtclipboard.h @@ -70,7 +70,7 @@ private: #ifndef Q_OS_WINPHONE Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IClipboardStatics> m_nativeClipBoard; #endif - QMimeData m_mimeData; + QMimeData *m_mimeData; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp index bad15126d4..42fe030b23 100644 --- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp @@ -108,6 +108,9 @@ bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModa Q_D(QWinRTMessageDialogHelper); QSharedPointer<QMessageDialogOptions> options = this->options(); + if (!options.data()) + return false; + const QString informativeText = options->informativeText(); const QString title = options->windowTitle(); const QString text = informativeText.isEmpty() ? options->text() : (options->text() + QLatin1Char('\n') + informativeText); diff --git a/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri b/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri index c2d3849d8e..68cb91ff3d 100644 --- a/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri +++ b/src/plugins/platforms/xcb/gl_integrations/gl_integrations_plugin_base.pri @@ -3,6 +3,8 @@ QT += core-private gui-private platformsupport-private xcb_qpa_lib-private INCLUDEPATH += $$PWD INCLUDEPATH += $$PWD/../ +load(qt_build_paths) + # needed by Xcursor ... contains(QT_CONFIG, xcb-xlib) { DEFINES += XCB_USE_XLIB diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index db9ea32cd8..9ca8872cb2 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -38,6 +38,8 @@ HEADERS = \ qxcbxsettings.h \ qxcbsystemtraytracker.h +load(qt_build_paths) + DEFINES += QT_BUILD_XCB_PLUGIN # needed by Xcursor ... contains(QT_CONFIG, xcb-xlib) { diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index a9d316095c..1c02d389fe 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -918,14 +918,14 @@ void QWin32PrintEnginePrivate::initialize() Q_ASSERT(hPrinter); Q_ASSERT(pInfo); + initHDC(); + if (devMode) { num_copies = devMode->dmCopies; devMode->dmCollate = DMCOLLATE_TRUE; updatePageLayout(); } - initHDC(); - #if defined QT_DEBUG_DRAW || defined QT_DEBUG_METRICS qDebug() << "QWin32PrintEngine::initialize()"; debugMetrics(); diff --git a/src/printsupport/kernel/qprintengine_win_p.h b/src/printsupport/kernel/qprintengine_win_p.h index c1d7b452f9..74b78ae2b1 100644 --- a/src/printsupport/kernel/qprintengine_win_p.h +++ b/src/printsupport/kernel/qprintengine_win_p.h @@ -124,10 +124,14 @@ public: state(QPrinter::Idle), resolution(0), m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0))), + stretch_x(1), stretch_y(1), origin_x(0), origin_y(0), + dpi_x(96), dpi_y(96), dpi_display(96), num_copies(1), printToFile(false), reinit(false), - embed_fonts(true) + complex_xform(false), has_pen(false), has_brush(false), has_custom_paper_size(false), + embed_fonts(true), + txop(0 /* QTransform::TxNone */) { } diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index 547a55f19e..c4cc21cbe5 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -2173,7 +2173,8 @@ QColor QColorDialog::getColor(const QColor &initial, QWidget *parent, const QStr QRgb QColorDialog::getRgba(QRgb initial, bool *ok, QWidget *parent) { - QColor color(getColor(QColor(initial), parent, QString(), ShowAlphaChannel)); + const QColor color = getColor(QColor::fromRgba(initial), parent, QString(), + ShowAlphaChannel); QRgb result = color.isValid() ? color.rgba() : initial; if (ok) *ok = color.isValid(); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 6729969024..b1d80d7b8f 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -10340,14 +10340,13 @@ void QWidgetPrivate::setWindowFlags(Qt::WindowFlags flags) // the old type was a window and/or the new type is a window QPoint oldPos = q->pos(); bool visible = q->isVisible(); + const bool windowFlagChanged = (q->data->window_flags ^ flags) & Qt::Window; q->setParent(q->parentWidget(), flags); // if both types are windows or neither of them are, we restore // the old position - if (!((q->data->window_flags ^ flags) & Qt::Window) - && (visible || q->testAttribute(Qt::WA_Moved))) { + if (!windowFlagChanged && (visible || q->testAttribute(Qt::WA_Moved))) q->move(oldPos); - } // for backward-compatibility we change Qt::WA_QuitOnClose attribute value only when the window was recreated. adjustQuitOnCloseAttribute(); } else { diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index cb3c2a410b..568a4755e4 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -996,15 +996,17 @@ QRenderRule::QRenderRule(const QVector<Declaration> &declarations, const QObject } } - if (const QWidget *widget = qobject_cast<const QWidget *>(object)) { - QStyleSheetStyle *style = const_cast<QStyleSheetStyle *>(globalStyleSheetStyle); - if (!style) - style = qobject_cast<QStyleSheetStyle *>(widget->style()); - if (style) - fixupBorder(style->nativeFrameWidth(widget)); + if (hasBorder()) { + if (const QWidget *widget = qobject_cast<const QWidget *>(object)) { + QStyleSheetStyle *style = const_cast<QStyleSheetStyle *>(globalStyleSheetStyle); + if (!style) + style = qobject_cast<QStyleSheetStyle *>(widget->style()); + if (style) + fixupBorder(style->nativeFrameWidth(widget)); + } + if (border()->hasBorderImage()) + defaultBackground = QBrush(); } - if (hasBorder() && border()->hasBorderImage()) - defaultBackground = QBrush(); } QRect QRenderRule::borderRect(const QRect& r) const diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index fe9684a25f..52006815ed 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -1175,9 +1175,9 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption case CE_MenuItem: if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { // windows always has a check column, regardless whether we have an icon or not - const qreal devicePixelRatio = QWindowsXPStylePrivate::devicePixelRatio(widget); - int checkcol = qRound(qreal(25) / devicePixelRatio); - const int gutterWidth = qRound(qreal(3) / devicePixelRatio); + const qreal factor = QWindowsXPStylePrivate::nativeMetricScaleFactor(widget); + int checkcol = qRound(qreal(25) * factor); + const int gutterWidth = qRound(qreal(3) * factor); { XPThemeData theme(widget, 0, QWindowsXPStylePrivate::MenuTheme, MENU_POPUPCHECKBACKGROUND, MBI_HOT); @@ -2166,8 +2166,9 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt const bool isToolTitle = false; const int height = tb->rect.height(); const int width = tb->rect.width(); - int buttonWidth = GetSystemMetrics(SM_CXSIZE) / QWindowsStylePrivate::devicePixelRatio(widget) - - int(QStyleHelper::dpiScaled(4)); + const int buttonWidth = + qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * QWindowsStylePrivate::nativeMetricScaleFactor(widget) + - QStyleHelper::dpiScaled(4)); const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget); const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0; diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp index f2ee8e0b47..3017707117 100644 --- a/src/widgets/styles/qwindowsxpstyle.cpp +++ b/src/widgets/styles/qwindowsxpstyle.cpp @@ -2098,7 +2098,7 @@ void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *op themeNumber = QWindowsXPStylePrivate::StatusTheme; partId = SP_GRIPPER; XPThemeData theme(0, p, themeNumber, partId, 0); - QSize size = (theme.size() / QWindowsStylePrivate::devicePixelRatio(widget)).toSize(); + QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize(); size.rheight()--; if (const QStyleOptionSizeGrip *sg = qstyleoption_cast<const QStyleOptionSizeGrip *>(option)) { switch (sg->corner) { @@ -2169,7 +2169,7 @@ void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *op QWindowsXPStylePrivate::ToolBarTheme, TP_SPLITBUTTONDROPDOWN); if (theme.isValid()) { - const QSize size = (theme.size() / QWindowsStylePrivate::devicePixelRatio(widget)).toSize(); + const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize(); mbiw = size.width(); mbih = size.height(); } @@ -2632,10 +2632,11 @@ void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *op QRect QWindowsXPStylePrivate::scrollBarGripperBounds(QStyle::State flags, const QWidget *widget, XPThemeData *theme) { const bool horizontal = flags & QStyle::State_Horizontal; - const QMargins contentsMargin = (theme->margins(theme->rect, TMT_SIZINGMARGINS) - / QWindowsStylePrivate::devicePixelRatio(widget)).toMargins(); + const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget); + const QMargins contentsMargin = + (theme->margins(theme->rect, TMT_SIZINGMARGINS) * factor).toMargins(); theme->partId = horizontal ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT; - const QSize size = (theme->size() / QWindowsStylePrivate::devicePixelRatio(widget)).toSize(); + const QSize size = (theme->size() * factor).toSize(); const int hSpace = theme->rect.width() - size.width(); const int vSpace = theme->rect.height() - size.height(); @@ -3793,12 +3794,13 @@ QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt { XPThemeData buttontheme(widget, 0, QWindowsXPStylePrivate::ButtonTheme, BP_PUSHBUTTON, PBS_NORMAL); if (buttontheme.isValid()) { - const qreal devicePixelRatio = QWindowsXPStylePrivate::devicePixelRatio(widget); - const QMarginsF borderSize = buttontheme.margins() / devicePixelRatio; + const qreal factor = QWindowsXPStylePrivate::nativeMetricScaleFactor(widget); + const QMarginsF borderSize = buttontheme.margins() * factor; if (!borderSize.isNull()) { - const qreal margin = qreal(2) / devicePixelRatio; + const qreal margin = qreal(2) * factor; sz.rwidth() += qRound(borderSize.left() + borderSize.right() - margin); - sz.rheight() += int(borderSize.bottom() + borderSize.top() - margin + devicePixelRatio - 1); + sz.rheight() += int(borderSize.bottom() + borderSize.top() - margin + + qreal(1) / factor - 1); } const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin) + 1); sz += QSize(qMax(pixelMetric(QStyle::PM_ScrollBarExtent, option, widget) @@ -4072,7 +4074,7 @@ QIcon QWindowsXPStyle::standardIcon(StandardPixmap standardIcon, XPThemeData theme(0, 0, QWindowsXPStylePrivate::WindowTheme, WP_RESTOREBUTTON, RBS_NORMAL); if (theme.isValid()) { - const QSize size = (themeSize.size() / QWindowsStylePrivate::devicePixelRatio(widget)).toSize(); + const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize(); QPixmap pm(size); pm.fill(Qt::transparent); QPainter p(&pm); diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index 854befd265..881db81ad4 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -1083,6 +1083,8 @@ void QAbstractSpinBox::keyPressEvent(QKeyEvent *event) } d->edit->event(event); + if (!d->edit->text().isEmpty()) + d->cleared = false; if (!isVisible()) d->ignoreUpdateEdit = true; } diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp index d22e89c6e1..1d10de904d 100644 --- a/src/widgets/widgets/qdockarealayout.cpp +++ b/src/widgets/widgets/qdockarealayout.cpp @@ -2604,6 +2604,21 @@ void QDockAreaLayout::remove(const QList<int> &path) docks[index].remove(path.mid(1)); } +void QDockAreaLayout::removePlaceHolder(const QString &name) +{ + QList<int> index = indexOfPlaceHolder(name); + if (!index.isEmpty()) + remove(index); + foreach (QDockWidgetGroupWindow *dwgw, mainWindow->findChildren<QDockWidgetGroupWindow *>( + QString(), Qt::FindDirectChildrenOnly)) { + index = dwgw->layoutInfo()->indexOfPlaceHolder(name); + if (!index.isEmpty()) { + dwgw->layoutInfo()->remove(index); + dwgw->destroyOrHideIfEmpty(); + } + } +} + static inline int qMax(int i1, int i2, int i3) { return qMax(i1, qMax(i2, i3)); } void QDockAreaLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list, @@ -3030,15 +3045,27 @@ QRect QDockAreaLayout::constrainedRect(QRect rect, QWidget* widget) bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget) { - QList<int> index = indexOfPlaceHolder(dockWidget->objectName()); - if (index.isEmpty()) - return false; + QDockAreaLayoutItem *item = 0; + foreach (QDockWidgetGroupWindow *dwgw, mainWindow->findChildren<QDockWidgetGroupWindow *>( + QString(), Qt::FindDirectChildrenOnly)) { + QList<int> index = dwgw->layoutInfo()->indexOfPlaceHolder(dockWidget->objectName()); + if (!index.isEmpty()) { + dockWidget->setParent(dwgw); + item = const_cast<QDockAreaLayoutItem *>(&dwgw->layoutInfo()->item(index)); + break; + } + } + if (!item) { + QList<int> index = indexOfPlaceHolder(dockWidget->objectName()); + if (index.isEmpty()) + return false; + item = const_cast<QDockAreaLayoutItem *>(&this->item(index)); + } - QDockAreaLayoutItem &item = this->item(index); - QPlaceHolderItem *placeHolder = item.placeHolderItem; + QPlaceHolderItem *placeHolder = item->placeHolderItem; Q_ASSERT(placeHolder != 0); - item.widgetItem = new QDockWidgetItem(dockWidget); + item->widgetItem = new QDockWidgetItem(dockWidget); if (placeHolder->window) { const QRect r = constrainedRect(placeHolder->topLevelRect, dockWidget); @@ -3050,7 +3077,7 @@ bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget) dockWidget->d_func()->setWindowState(true); #endif - item.placeHolderItem = 0; + item->placeHolderItem = 0; delete placeHolder; return true; @@ -3086,9 +3113,7 @@ void QDockAreaLayout::addDockWidget(QInternal::DockPosition pos, QDockWidget *do info = new_info; } - QList<int> index = indexOfPlaceHolder(dockWidget->objectName()); - if (!index.isEmpty()) - remove(index); + removePlaceHolder(dockWidget->objectName()); } void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second) @@ -3101,9 +3126,7 @@ void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second) Q_ASSERT(info != 0); info->tab(path.last(), new QDockWidgetItem(second)); - QList<int> index = indexOfPlaceHolder(second->objectName()); - if (!index.isEmpty()) - remove(index); + removePlaceHolder(second->objectName()); } void QDockAreaLayout::resizeDocks(const QList<QDockWidget *> &docks, @@ -3165,9 +3188,7 @@ void QDockAreaLayout::splitDockWidget(QDockWidget *after, Q_ASSERT(info != 0); info->split(path.last(), orientation, new QDockWidgetItem(dockWidget)); - QList<int> index = indexOfPlaceHolder(dockWidget->objectName()); - if (!index.isEmpty()) - remove(index); + removePlaceHolder(dockWidget->objectName()); } void QDockAreaLayout::apply(bool animate) diff --git a/src/widgets/widgets/qdockarealayout_p.h b/src/widgets/widgets/qdockarealayout_p.h index 5d352f0124..8a35d8b035 100644 --- a/src/widgets/widgets/qdockarealayout_p.h +++ b/src/widgets/widgets/qdockarealayout_p.h @@ -255,6 +255,7 @@ public: QLayoutItem *plug(const QList<int> &path); QLayoutItem *unplug(const QList<int> &path); void remove(const QList<int> &path); + void removePlaceHolder(const QString &name); void fitLayout(); diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index 6b247d8d11..f581fe4d88 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -215,11 +215,10 @@ public: } void setGeometry(const QRect&r) Q_DECL_OVERRIDE { + static_cast<QDockWidgetGroupWindow *>(parent())->destroyOrHideIfEmpty(); QDockAreaLayoutInfo *li = layoutInfo(); - if (li->isEmpty()) { - static_cast<QDockWidgetGroupWindow *>(parent())->destroyIfEmpty(); + if (li->isEmpty()) return; - } int fw = frameWidth(); li->reparentWidgets(parentWidget()); li->rect = r.adjusted(fw, fw, -fw, -fw); @@ -272,6 +271,10 @@ bool QDockWidgetGroupWindow::event(QEvent *e) if (qobject_cast<QDockWidget *>(static_cast<QChildEvent*>(e)->child())) adjustFlags(); break; + case QEvent::LayoutRequest: + // We might need to show the widget again + destroyOrHideIfEmpty(); + break; default: break; } @@ -325,34 +328,43 @@ QDockWidget *QDockWidgetGroupWindow::topDockWidget() const } /*! \internal - Destroy this window if there is no more QDockWidget in it. + Destroy or hide this window if there is no more QDockWidget in it. + Otherwise make sure it is shown. */ -void QDockWidgetGroupWindow::destroyIfEmpty() -{ - if (layoutInfo()->isEmpty()) { - // Make sure to reparent the possibly floating or hidden QDockWidgets to the parent - foreach (QDockWidget *dw, - findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly)) { - bool wasFloating = dw->isFloating(); - bool wasHidden = dw->isHidden(); - dw->setParent(parentWidget()); - if (wasFloating) { - dw->setFloating(true); - } else { - // maybe it was hidden, we still have to put it back in the main layout. - QMainWindowLayout *ml = qt_mainwindow_layout(static_cast<QMainWindow*>(parentWidget())); - Qt::DockWidgetArea area = ml->dockWidgetArea(this); - if (area == Qt::NoDockWidgetArea) - area = Qt::LeftDockWidgetArea; - static_cast<QMainWindow*>(parentWidget())->addDockWidget(area, dw); - } - if (!wasHidden) - dw->show(); +void QDockWidgetGroupWindow::destroyOrHideIfEmpty() +{ + if (!layoutInfo()->isEmpty()) { + show(); // It might have been hidden, + return; + } + // There might still be placeholders + if (!layoutInfo()->item_list.isEmpty()) { + hide(); + return; + } + + // Make sure to reparent the possibly floating or hidden QDockWidgets to the parent + foreach (QDockWidget *dw, findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly)) { + bool wasFloating = dw->isFloating(); + bool wasHidden = dw->isHidden(); + dw->setParent(parentWidget()); + if (wasFloating) { + dw->setFloating(true); + } else { + // maybe it was hidden, we still have to put it back in the main layout. + QMainWindowLayout *ml = + qt_mainwindow_layout(static_cast<QMainWindow *>(parentWidget())); + Qt::DockWidgetArea area = ml->dockWidgetArea(this); + if (area == Qt::NoDockWidgetArea) + area = Qt::LeftDockWidgetArea; + static_cast<QMainWindow *>(parentWidget())->addDockWidget(area, dw); } - foreach (QTabBar *tb, findChildren<QTabBar *>(QString(), Qt::FindDirectChildrenOnly)) - tb->setParent(parentWidget()); - deleteLater(); + if (!wasHidden) + dw->show(); } + foreach (QTabBar *tb, findChildren<QTabBar *>(QString(), Qt::FindDirectChildrenOnly)) + tb->setParent(parentWidget()); + deleteLater(); } /*! \internal @@ -2075,7 +2087,7 @@ void QMainWindowLayout::animationFinished(QWidget *widget) item.subinfo->reparentWidgets(parentWidget()); item.subinfo->setTabBarShape(parentInfo->tabBarShape); } - dwgw->destroyIfEmpty(); + dwgw->destroyOrHideIfEmpty(); } if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) { diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h index 9a13e5f5ce..7475da8bdc 100644 --- a/src/widgets/widgets/qmainwindowlayout_p.h +++ b/src/widgets/widgets/qmainwindowlayout_p.h @@ -86,7 +86,7 @@ public: : QWidget(parent, f) {} QDockAreaLayoutInfo *layoutInfo() const; QDockWidget *topDockWidget() const; - void destroyIfEmpty(); + void destroyOrHideIfEmpty(); void adjustFlags(); protected: bool event(QEvent *) Q_DECL_OVERRIDE; diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp index bbc086b048..9ca7e0001a 100644 --- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp +++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp @@ -132,6 +132,7 @@ tst_QMimeDatabase::tst_QMimeDatabase() void tst_QMimeDatabase::initTestCase() { + QLocale::setDefault(QLocale::c()); QVERIFY2(m_temporaryDir.isValid(), qPrintable(m_temporaryDir.errorString())); QStandardPaths::setTestModeEnabled(true); m_localMimeDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/mime"; @@ -450,6 +451,21 @@ void tst_QMimeDatabase::icons() QCOMPARE(pub.genericIconName(), QString::fromLatin1("x-office-document")); } +void tst_QMimeDatabase::comment() +{ + struct RestoreLocale + { + ~RestoreLocale() { QLocale::setDefault(QLocale::c()); } + } restoreLocale; + + QLocale::setDefault(QLocale("de")); + QMimeDatabase db; + QMimeType directory = db.mimeTypeForName(QStringLiteral("inode/directory")); + QCOMPARE(directory.comment(), QStringLiteral("Ordner")); + QLocale::setDefault(QLocale("fr")); + QCOMPARE(directory.comment(), QStringLiteral("dossier")); +} + // In here we do the tests that need some content in a temporary file. // This could also be added to shared-mime-info's testsuite... void tst_QMimeDatabase::mimeTypeForFileWithContent() diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h index 4b703f15d7..4d9a360dd9 100644 --- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h +++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.h @@ -60,6 +60,7 @@ private slots: void listAliases_data(); void listAliases(); void icons(); + void comment(); void mimeTypeForFileWithContent(); void mimeTypeForUrl(); void mimeTypeForData_data(); diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp index 02e2bf27e2..bb20d99e30 100644 --- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp +++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp @@ -323,6 +323,8 @@ void tst_QTextDocument::find_data() << 15 << 6 << 11; QTest::newRow("nbsp") << "Hello" + QString(QChar(QChar::Nbsp)) +"World" << " " << int(QTextDocument::FindCaseSensitively) << 0 << 5 << 6; + + QTest::newRow("from-the-end") << "Hello World" << "Hello World" << int(QTextDocument::FindCaseSensitively| QTextDocument::FindBackward) << 11 << 0 << 11; } void tst_QTextDocument::find() diff --git a/tests/auto/testlib/selftests/generate_expected_output.py b/tests/auto/testlib/selftests/generate_expected_output.py index b917dacc78..1bf8cf6603 100755 --- a/tests/auto/testlib/selftests/generate_expected_output.py +++ b/tests/auto/testlib/selftests/generate_expected_output.py @@ -32,89 +32,185 @@ ## ############################################################################# -#regenerate all test's output +# Regenerate all tests' output. +# +# Usage: cd to the build directory corresponding to this script's +# location; invoke this script; optionally pass the names of sub-dirs +# to limit which tests to regenerate expected_* files for. import os -import sys import subprocess -import re - -formats = ['xml', 'txt', 'xunitxml', 'lightxml'] - -qtver = subprocess.check_output(['qmake', '-query', 'QT_VERSION']).strip().decode('utf-8') -rootPath = os.getcwd() - -isWindows = sys.platform == 'win32' - -replacements = [ - (qtver, r'@INSERT_QT_VERSION_HERE@'), - (r'Config: Using QtTest library.*', r'Config: Using QtTest library'), # Build string in text logs - (rootPath.encode('unicode-escape').decode('utf-8'), r''), - (r'( *)<Duration msecs="[\d\.]+"/>', r'\1<Duration msecs="0"/>'), - (r'( *)<QtBuild>[^<]+</QtBuild>', r'\1<QtBuild/>'), # Build element in xml, lightxml - (r'<property value="[^"]+" name="QtBuild"/>', r'<property value="" name="QtBuild"/>') # Build in xunitxml -] - -extraArgs = { - "commandlinedata": "fiveTablePasses fiveTablePasses:fiveTablePasses_data1 -v2", - "benchlibcallgrind": "-callgrind", - "benchlibeventcounter": "-eventcounter", - "benchliboptions": "-eventcounter", - "benchlibtickcounter": "-tickcounter", - "badxml": "-eventcounter", - "benchlibcounting": "-eventcounter", - "printdatatags": "-datatags", - "printdatatagswithglobaltags": "-datatags", - "silent": "-silent", - "verbose1": "-v1", - "verbose2": "-v2", -} - -# Replace all occurrences of searchExp in one file -def replaceInFile(file): - import sys - import fileinput - for line in fileinput.input(file, inplace=1): - for searchExp, replaceExp in replacements: - line = re.sub(searchExp, replaceExp, line) - sys.stdout.write(line) - -def subdirs(): - result = [] - for path in os.listdir('.'): - if os.path.isdir('./' + path): - result.append(path) - return result - -def getTestForPath(path): - if isWindows: - testpath = path + '\\' + path + '.exe' - else: - testpath = path + '/' + path - return testpath - -def generateTestData(testname): - print(" running " + testname) + +class Fail (Exception): pass + +class Cleaner (object): + """Tool to clean up test output to make diff-ing runs useful. + + We care about whether tests pass or fail - if that changes, + something that matters has happened - and we care about some + changes to what they say when they do fail; but we don't care + exactly what line of what file the failing line of code now + occupies, nor do we care how many milliseconds each test took to + run; and changes to the Qt version number mean nothing to us. + + Create one singleton instance; it'll do mildly expensive things + once and you can use its .clean() method to tidy up your test + output.""" + + def __init__(self, here, command): + """Set up the details we need for later cleaning. + + Takes two parameters: here is $PWD and command is how this + script was invoked, from which we'll work out where it is; in + a shadow build, the former is the build tree's location + corresponding to this last. Checks $PWD does look as expected + in a build tree - raising Fail() if not - then invokes qmake + to discover Qt version (saved as .version for the benefit of + clients) and prepares the sequence of (regex, replace) pairs + that .clean() needs to do its job.""" + self.version, self.__replace = self.__getPatterns(here, command) + + import re + @staticmethod + def __getPatterns(here, command, + patterns = ( + # Timings: + (r'( *<Duration msecs=)"[\d\.]+"/>', r'\1"0"/>'), # xml, lightxml + (r'(Totals:.*,) *[0-9.]+ms', r'\1 0ms'), # txt + # Benchmarks: + (r'[0-9,.]+( (?:CPU ticks|msecs) per iteration \(total:) [0-9,.]+ ', r'0\1 0, '), # txt + (r'(,"(?:CPUTicks|WalltimeMilliseconds)"),\d+,\d+,', r'\1,0,0,'), # csv + (r'(<BenchmarkResult metric="(?:CPUTicks|WalltimeMilliseconds)".*\bvalue=)"[^"]+"', r'\1"0"'), # xml, lightxml + # Build details: + (r'(Config: Using QtTest library).*', r'\1'), # txt + (r'( *<QtBuild)>[^<]+</QtBuild>', r'\1/>'), # xml, lightxml + (r'(<property value=")[^"]+(" name="QtBuild"/>)', r'\1\2'), # xunitxml + # Line numbers in source files: + (r'(Loc: \[[^[\]()]+)\(\d+\)', r'\1(0)'), # txt + # (r'(\[Loc: [^[\]()]+)\(\d+\)', r'\1(0)'), # teamcity + (r'(<Incident.*\bfile=.*\bline=)"\d+"', r'\1"0"'), # lightxml, xml + ), + precook = re.compile): + """Private implementation details of __init__().""" + + qmake = ('..',) * 4 + ('bin', 'qmake') + qmake = os.path.join(*qmake) + + if os.path.sep in command: + scriptPath = os.path.abspath(command) + elif os.path.exists(command): + # e.g. if you typed "python3 generate_expected_output.py" + scriptPath = os.path.join(here, command) + else: + # From py 3.2: could use os.get_exec_path() here. + for d in os.environ.get('PATH', '').split(os.pathsep): + scriptPath = os.path.join(d, command) + if os.path.isfile(scriptPath): + break + else: # didn't break + raise Fail('Unable to find', command, 'in $PATH') + + # Are we being run from the right place ? + myNames = scriptPath.split(os.path.sep) + if not (here.split(os.path.sep)[-5:] == myNames[-6:-1] + and os.path.isfile(qmake)): + raise Fail('Run', myNames[-1], 'in its directory of a completed build') + + try: + qtver = subprocess.check_output([qmake, '-query', 'QT_VERSION']) + except OSError as what: + raise Fail(what.strerror) + qtver = qtver.strip().decode('utf-8') + + scriptPath = os.path.dirname(scriptPath) # ditch leaf file-name + sentinel = os.path.sep + 'qtbase' + os.path.sep # '/qtbase/' + # Identify the path prefix of our qtbase ancestor directory + # (source, build and $PWD, when different); trim such prefixes + # off all paths we see. + roots = tuple(r[:r.find(sentinel) + 1].encode('unicode-escape').decode('utf-8') + for r in set((here, scriptPath, os.environ.get('PWD', ''))) + if sentinel in r) + patterns += tuple((root, r'') for root in roots) + ( + (r'\.'.join(qtver.split('.')), r'@INSERT_QT_VERSION_HERE@'),) + if any('-' in r for r in roots): + # Our xml formats replace hyphens with a character entity: + patterns += tuple((root.replace('-', '�*2D;'), r'') + for root in roots if '-' in root) + + return qtver, tuple((precook(p), r) for p, r in patterns) + del re + + def clean(self, data): + """Remove volatile details from test output. + + Takes the full test output as a single (possibly huge) + multi-line string; iterates over cleaned lines of output.""" + for line in data.split('\n'): + # Replace all occurrences of each regex: + for searchRe, replaceExp in self.__replace: + line = searchRe.sub(replaceExp, line) + yield line + +def generateTestData(testname, clean, + formats = ('xml', 'csv', 'txt', 'xunitxml', 'lightxml'), # +'teamcity' in 5.7 + extraArgs = { + "commandlinedata": "fiveTablePasses fiveTablePasses:fiveTablePasses_data1 -v2", + "benchlibcallgrind": "-callgrind", + "benchlibeventcounter": "-eventcounter", + "benchliboptions": "-eventcounter", + "benchlibtickcounter": "-tickcounter", + "badxml": "-eventcounter", + "benchlibcounting": "-eventcounter", + "printdatatags": "-datatags", + "printdatatagswithglobaltags": "-datatags", + "silent": "-silent", + "verbose1": "-v1", + "verbose2": "-v2", + }): + """Run one test and save its cleaned results. + + Required arguments are the name of the test directory (the binary + it contains is expected to have the same name) and a function + that'll clean a test-run's output; see Cleaner.clean(). + """ + # MS-Win: shall need to add .exe to this + path = os.path.join(testname, testname) + if not os.path.isfile(path): + print("Warning: directory", testname, "contains no test executable") + return + + print(" running", testname) for format in formats: - cmd = [getTestForPath(testname) + ' -' + format + ' ' + extraArgs.get(testname, '')] - result = 'expected_' + testname + '.' + format - data = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).communicate()[0] - out = open(result, 'w') - out.write(data) - out.close() - replaceInFile(result) - -if isWindows: - print("This script does not work on Windows.") - exit() - -tests = sys.argv[1:] -os.environ['LC_ALL'] = 'C' -if len(tests) == 0: - tests = subdirs() -print("Generating " + str(len(tests)) + " test results for: " + qtver + " in: " + rootPath) -for path in tests: - if os.path.isfile(getTestForPath(path)): - generateTestData(path) - else: - print("Warning: directory " + path + " contains no test executable") + cmd = [path, '-' + format] + if testname in extraArgs: + cmd += extraArgs[testname].split() + + data = subprocess.Popen(cmd, stdout=subprocess.PIPE, + universal_newlines=True).communicate()[0] + with open('expected_' + testname + '.' + format, 'w') as out: + out.write('\n'.join(clean(data))) # write() appends a newline, too + +def main(name, *args): + """Minimal argument parsing and driver for the real work""" + os.environ['LC_ALL'] = 'C' + herePath = os.getcwd() + cleaner = Cleaner(herePath, name) + + tests = args if args else [d for d in os.listdir('.') if os.path.isdir(d)] + print("Generating", len(tests), "test results for", cleaner.version, "in:", herePath) + for path in tests: + generateTestData(path, cleaner.clean) + +if __name__ == '__main__': + # Executed when script is run, not when imported (e.g. to debug) + import sys + + if sys.platform.startswith('win'): + print("This script does not work on Windows.") + exit() + + try: + main(*sys.argv) + except Fail as what: + sys.stderr.write('Failed: ' + ' '.join(what.args) + '\n') + exit(1) diff --git a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp index 34b05c5291..6d011eed59 100644 --- a/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp +++ b/tests/auto/widgets/widgets/qspinbox/tst_qspinbox.cpp @@ -143,6 +143,8 @@ private slots: void positiveSign(); + void interpretOnLosingFocus(); + void setGroupSeparatorShown_data(); void setGroupSeparatorShown(); @@ -1150,6 +1152,33 @@ void tst_QSpinBox::positiveSign() QCOMPARE(spinBox.text(), QLatin1String("+20")); } +void tst_QSpinBox::interpretOnLosingFocus() +{ + // QTBUG-55249: When typing an invalid value after QSpinBox::clear(), + // it should be fixed up on losing focus. + + static const int minimumValue = 10; + static const int maximumValue = 20; + + QWidget widget; + widget.setWindowTitle(QTest::currentTestFunction()); + QVBoxLayout *layout = new QVBoxLayout(&widget); + QLineEdit *focusDummy = new QLineEdit("focusDummy", &widget); + layout->addWidget(focusDummy); + SpinBox *spinBox = new SpinBox(&widget); + spinBox->setRange(minimumValue, maximumValue); + spinBox->setValue(minimumValue); + layout->addWidget(spinBox); + spinBox->clear(); + spinBox->setFocus(); + widget.show(); + QVERIFY(QTest::qWaitForWindowActive(&widget)); + QTest::keyClick(spinBox, Qt::Key_1); // Too small + focusDummy->setFocus(); + QCOMPARE(spinBox->value(), minimumValue); + QCOMPARE(spinBox->lineEdit()->text().toInt(), minimumValue); +} + void tst_QSpinBox::setGroupSeparatorShown_data() { QTest::addColumn<QLocale::Language>("lang"); diff --git a/tests/manual/qopenglwindow/multiwindow/main.cpp b/tests/manual/qopenglwindow/multiwindow/main.cpp index 47616ded0f..caa15078d5 100644 --- a/tests/manual/qopenglwindow/multiwindow/main.cpp +++ b/tests/manual/qopenglwindow/multiwindow/main.cpp @@ -37,26 +37,22 @@ #include <QOpenGLFunctions> #include <QPainter> #include <QElapsedTimer> +#include <QCommandLineParser> +#include <QScreen> + +const char applicationDescription[] = "\n\ +This application opens multiple windows and continuously schedules updates for\n\ +them. Each of them is a separate QOpenGLWindow so there will be a separate\n\ +context and swapBuffers call for each.\n\ +\n\ +By default the swap interval is 1 so the effect of multiple blocking swapBuffers\n\ +on the main thread can be examined. (the result is likely to be different\n\ +between platforms, for example OS X is buffer queuing meaning that it can\n\ +block outside swap, resulting in perfect vsync for all three windows, while\n\ +other systems that block on swap will kill the frame rate due to blocking the\n\ +thread three times)\ +"; -// This application opens three windows and continuously schedules updates for -// them. Each of them is a separate QOpenGLWindow so there will be a separate -// context and swapBuffers call for each. -// -// By default the swap interval is 1 so the effect of three blocking swapBuffers -// on the main thread can be examined. (the result is likely to be different -// between platforms, for example OS X is buffer queuing meaning that it can -// block outside swap, resulting in perfect vsync for all three windows, while -// other systems that block on swap will kill the frame rate due to blocking the -// thread three times) -// -// Pass --novsync to set a swap interval of 0. This should give an unthrottled -// refresh on all platforms for all three windows. -// -// Passing --vsyncone sets swap interval to 1 for the first window and 0 to the -// others. -// -// Pass --extrawindows N to open N windows in addition to the default 3. -// // For reference, below is a table of some test results. // // swap interval 1 for all swap interval 1 for only one and 0 for others @@ -69,12 +65,15 @@ class Window : public QOpenGLWindow { + Q_OBJECT public: Window(int n) : idx(n) { r = g = b = fps = 0; y = 0; resize(200, 200); - t2.start(); + + connect(this, SIGNAL(frameSwapped()), SLOT(frameSwapped())); + fpsTimer.start(); } void paintGL() { @@ -106,27 +105,52 @@ public: if (y > height() - 20) y = 20; - if (t2.elapsed() > 1000) { - fps = 1000.0 / t.elapsed(); - t2.restart(); - } - t.restart(); - update(); } +public slots: + void frameSwapped() { + ++framesSwapped; + if (fpsTimer.elapsed() > 1000) { + fps = qRound(framesSwapped * (1000.0 / fpsTimer.elapsed())); + framesSwapped = 0; + fpsTimer.restart(); + } + } + private: int idx; - GLfloat r, g, b, fps; + GLfloat r, g, b; int y; - QElapsedTimer t, t2; + + int framesSwapped; + QElapsedTimer fpsTimer; + int fps; }; int main(int argc, char **argv) { QGuiApplication app(argc, argv); + + QCommandLineParser parser; + parser.setApplicationDescription(applicationDescription); + parser.addHelpOption(); + + QCommandLineOption noVsyncOption("novsync", "Disable Vsync by setting swap interval to 0. " + "This should give an unthrottled refresh on all platforms for all windows."); + parser.addOption(noVsyncOption); + + QCommandLineOption vsyncOneOption("vsyncone", "Enable Vsync only for first window, " + "by setting swap interval to 1 for the first window and 0 for the others."); + parser.addOption(vsyncOneOption); + + QCommandLineOption numWindowsOption("numwindows", "Open <N> windows instead of the default 3.", "N", "3"); + parser.addOption(numWindowsOption); + + parser.process(app); + QSurfaceFormat fmt; - if (QGuiApplication::arguments().contains(QLatin1String("--novsync"))) { + if (parser.isSet(noVsyncOption)) { qDebug("swap interval 0 (no throttling)"); fmt.setSwapInterval(0); } else { @@ -134,36 +158,41 @@ int main(int argc, char **argv) } QSurfaceFormat::setDefaultFormat(fmt); - Window w1(0); - if (QGuiApplication::arguments().contains(QLatin1String("--vsyncone"))) { - qDebug("swap interval 1 for first window only"); - QSurfaceFormat w1fmt = fmt; - w1fmt.setSwapInterval(1); - w1.setFormat(w1fmt); - fmt.setSwapInterval(0); - QSurfaceFormat::setDefaultFormat(fmt); - } - Window w2(1); - Window w3(2); - w1.setGeometry(QRect(QPoint(10, 100), w1.size())); - w2.setGeometry(QRect(QPoint(300, 100), w2.size())); - w3.setGeometry(QRect(QPoint(600, 100), w3.size())); - w1.show(); - w2.show(); - w3.show(); - - QList<QWindow *> extraWindows; - int countIdx; - if ((countIdx = QGuiApplication::arguments().indexOf(QLatin1String("--extrawindows"))) >= 0) { - int extraWindowCount = QGuiApplication::arguments().at(countIdx + 1).toInt(); - for (int i = 0; i < extraWindowCount; ++i) { - Window *w = new Window(3 + i); - extraWindows << w; - w->show(); + QRect availableGeometry = app.primaryScreen()->availableGeometry(); + + int numberOfWindows = qMax(parser.value(numWindowsOption).toInt(), 1); + QList<QWindow *> windows; + for (int i = 0; i < numberOfWindows; ++i) { + Window *w = new Window(i + 1); + windows << w; + + if (i == 0 && parser.isSet(vsyncOneOption)) { + qDebug("swap interval 1 for first window only"); + QSurfaceFormat vsyncedSurfaceFormat = fmt; + vsyncedSurfaceFormat.setSwapInterval(1); + w->setFormat(vsyncedSurfaceFormat); + fmt.setSwapInterval(0); + QSurfaceFormat::setDefaultFormat(fmt); } + + static int windowWidth = w->width() + 20; + static int windowHeight = w->height() + 20; + + static int windowsPerRow = availableGeometry.width() / windowWidth; + + int col = i; + int row = col / windowsPerRow; + col -= row * windowsPerRow; + + QPoint position = availableGeometry.topLeft(); + position += QPoint(col * windowWidth, row * windowHeight); + w->setFramePosition(position); + w->show(); } int r = app.exec(); - qDeleteAll(extraWindows); + qDeleteAll(windows); return r; } + +#include "main.moc" |