diff --git a/config.tests/unix/compile.test b/config.tests/unix/compile.test index 22064b85e9..f99237cb50 100755 --- a/config.tests/unix/compile.test +++ b/config.tests/unix/compile.test @@ -69,15 +69,11 @@ rm -f "$EXE" "${EXE}.exe" set -- "$OUTDIR/bin/qmake" -nocache -spec "$QMKSPEC" "CONFIG+=$QMAKE_CONFIG" "CONFIG+=android_app" "CONFIG-=debug_and_release app_bundle lib_bundle" "LIBS*=$LFLAGS" "LIBS+=$MAC_ARCH_LFLAGS" "INCLUDEPATH*=$INCLUDEPATH" "QMAKE_CXXFLAGS*=$CXXFLAGS" "QMAKE_CXXFLAGS+=$MAC_ARCH_CXXFLAGS" "QT_BUILD_TREE=$OUTDIR" "$SRCDIR/$TEST/$EXE.pro" -o "$OUTDIR/$TEST/Makefile" if [ "$VERBOSE" = "yes" ]; then - OUTDIR=$OUTDIR "$@" - $MAKE + OUTDIR=$OUTDIR "$@" && $MAKE && SUCCESS=yes else - OUTDIR=$OUTDIR "$@" >/dev/null 2>&1 - $MAKE >/dev/null 2>&1 + OUTDIR=$OUTDIR "$@" >/dev/null 2>&1 && $MAKE >/dev/null 2>&1 && SUCCESS=yes fi -( [ -f "$EXE" ] || [ -f "${EXE}.exe" ] ) && SUCCESS=yes - # done if [ "$SUCCESS" != "yes" ]; then [ "$VERBOSE" = "yes" ] && echo "$DESCRIPTION disabled." diff --git a/config.tests/unix/icu/icu.pro b/config.tests/unix/icu/icu.pro index 2c1b431f92..16267ff827 100644 --- a/config.tests/unix/icu/icu.pro +++ b/config.tests/unix/icu/icu.pro @@ -1,6 +1,7 @@ SOURCES = icu.cpp CONFIG += console CONFIG -= qt dylib + win32 { CONFIG(static, static|shared) { CONFIG(debug, debug|release) { @@ -9,8 +10,8 @@ win32 { LIBS += -lsicuin -lsicuuc -lsicudt } } else { - LIBS += -licuin -licuuc + LIBS += -licuin -licuuc -licudt } } else { - LIBS += -licui18n -licuuc + LIBS += -licui18n -licuuc -licudata } diff --git a/config.tests/unix/objcopy.test b/config.tests/unix/objcopy.test deleted file mode 100755 index 9eb6e22ab0..0000000000 --- a/config.tests/unix/objcopy.test +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh - -TEST_PATH=`dirname "$0"` -SEP_DEBUG_SUPPORT=no -COMPILER=$1 -QMAKE_OBJCOPY=$2 -VERBOSE=$3 - -if [ -n "$QMAKE_OBJCOPY" ]; then - echo "int main() { return 0; }" > objcopy_test.cpp - if $TEST_PATH/which.test "$QMAKE_OBJCOPY" >/dev/null 2>&1 && $COMPILER $SYSROOT_FLAG -g -o objcopy_test objcopy_test.cpp >/dev/null 2>&1; then - "$QMAKE_OBJCOPY" --only-keep-debug objcopy_test objcopy_test.debug >/dev/null 2>&1 \ - && "$QMAKE_OBJCOPY" --strip-debug objcopy_test >/dev/null 2>&1 \ - && "$QMAKE_OBJCOPY" --add-gnu-debuglink=objcopy_test.debug objcopy_test >/dev/null 2>&1 \ - && SEP_DEBUG_SUPPORT=yes - fi - rm -f objcopy_test objcopy_test.debug objcopy_test.cpp -else - [ "$VERBOSE" = "yes" ] && echo "Separate debug info check skipped, QMAKE_OBJCOPY is unset."; -fi - -# done -if [ "$SEP_DEBUG_SUPPORT" != "yes" ]; then - [ "$VERBOSE" = "yes" ] && echo "Separate debug info support disabled." - exit 0 -else - [ "$VERBOSE" = "yes" ] && echo "Separate debug info support enabled." - exit 1 -fi diff --git a/config.tests/unix/objcopy/objcopy.cpp b/config.tests/unix/objcopy/objcopy.cpp new file mode 100644 index 0000000000..66b261bd6d --- /dev/null +++ b/config.tests/unix/objcopy/objcopy.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BlackBerry Limited. All rights reserved. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +int main() +{ + return 0; +} diff --git a/config.tests/unix/objcopy/objcopy.pro b/config.tests/unix/objcopy/objcopy.pro new file mode 100644 index 0000000000..3c28b89ef3 --- /dev/null +++ b/config.tests/unix/objcopy/objcopy.pro @@ -0,0 +1,4 @@ +SOURCES = objcopy.cpp +CONFIG -= qt + +QMAKE_POST_LINK += $$QMAKE_OBJCOPY --only-keep-debug objcopy objcopy.debug && $$QMAKE_OBJCOPY --strip-debug objcopy && $$QMAKE_OBJCOPY --add-gnu-debuglink=objcopy.debug objcopy diff --git a/configure b/configure index dbb47ff1b7..dfda7c05d3 100755 --- a/configure +++ b/configure @@ -616,7 +616,7 @@ CFG_EGL=auto CFG_EGL_X=auto CFG_FONTCONFIG=auto CFG_FREETYPE=auto -CFG_HARFBUZZ=no +CFG_HARFBUZZ=auto CFG_SQL_AVAILABLE= QT_ALL_BUILD_PARTS=" libs tools examples tests " QT_DEFAULT_BUILD_PARTS="libs tools examples" @@ -781,8 +781,6 @@ QT_LIBS_GLIB= # default qpa platform QT_QPA_DEFAULT_PLATFORM= -# default print support plugin -QT_PRINTSUPPORT_DEFAULT_PLUGIN= # Android vars CFG_DEFAULT_ANDROID_NDK_ROOT=$ANDROID_NDK_ROOT @@ -1806,6 +1804,20 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; + pulseaudio) + if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then + CFG_PULSEAUDIO="$VAL" + else + UNKNOWN_OPT=yes + fi + ;; + alsa) + if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then + CFG_ALSA="$VAL" + else + UNKNOWN_OPT=yes + fi + ;; gtkstyle) if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then CFG_QGTKSTYLE="$VAL" @@ -2370,6 +2382,15 @@ Third Party Libraries: -no-glib ........... Do not compile Glib support. + -glib .............. Compile Glib support. + -no-pulseaudio ..... Do not compile PulseAudio support. + + -pulseaudio ........ Compile PulseAudio support. + + -no-alsa ........... Do not compile ALSA support. + + -alsa .............. Compile ALSA support. + + -no-gtkstyle ....... Do not compile GTK theme support. + + -gtkstyle .......... Compile GTK theme support. + Additional options: -make ....... Add part to the list of parts to be built at make time. @@ -3104,7 +3125,7 @@ if [ "$XPLATFORM_IOS" = "yes" ]; then CFG_PKGCONFIG="no" CFG_NOBUILD_PARTS="$CFG_NOBUILD_PARTS examples" CFG_SHARED="no" # iOS builds should be static to be able to submit to the App Store - CFG_SKIP_MODULES="$CFG_SKIP_MODULES qtconnectivity qtdoc qtmacextras qtserialport qttools qtwebkit qtwebkit-examples" + CFG_SKIP_MODULES="$CFG_SKIP_MODULES qtconnectivity qtdoc qtmacextras qtserialport qtwebkit qtwebkit-examples" # If the user passes -sdk on the command line we build a SDK-specific Qt build. # Otherwise we build a joined simulator and device build, which is the default. @@ -3179,7 +3200,7 @@ if [ "$CFG_PRECOMPILE" = "auto" ]; then fi fi -# auto-detect support for separate debug info in objcopy +# sanity-check for separate debug info if [ "$CFG_SEPARATE_DEBUG_INFO" = "yes" ]; then if [ "$CFG_SHARED" = "no" ]; then echo "ERROR: -separate-debug-info is incompatible with -static" @@ -3189,13 +3210,6 @@ if [ "$CFG_SEPARATE_DEBUG_INFO" = "yes" ]; then echo "ERROR: -separate-debug-info needs -debug, -debug-and-release, or -force-debug-info" exit 1 fi - TEST_OBJCOPY=`getXQMakeConf QMAKE_OBJCOPY` - COMPILER_WITH_FLAGS="$TEST_COMPILER $TEST_COMPILER_CXXFLAGS" - if "$unixtests/objcopy.test" "$COMPILER_WITH_FLAGS" "$TEST_OBJCOPY" "$OPT_VERBOSE"; then - echo "ERROR: -separate-debug-info was requested but this binutils does not support it." - echo "Re-run configure with -v for more information" - exit 1 - fi fi # auto-detect -fvisibility support @@ -3937,6 +3951,15 @@ fi # functionality tests #------------------------------------------------------------------------------- +# Detect objcopy support +if [ "$CFG_SEPARATE_DEBUG_INFO" = "yes" ]; then + if ! compileTest unix/objcopy "objcopy"; then + echo "ERROR: -separate-debug-info was requested but this binutils does not support it." + echo "Re-run configure with -v for more information" + exit 1 + fi +fi + # Detect C++11 support if [ "$CFG_CXX11" != "no" ]; then # Configure detects compiler features based on cross compiler, so we need @@ -4618,7 +4641,7 @@ if [ "$CFG_GLIB" = "yes" -a "$CFG_QGTKSTYLE" != "no" ]; then QMakeVar set QT_LIBS_QGTK2 "$QT_LIBS_QGTK2" else if [ "$CFG_QGTKSTYLE" = "yes" ] && [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then - echo "Gtk theme support cannot be enabled due to functionality tests!" + echo "GTK theme support cannot be enabled due to functionality tests!" echo " Turn on verbose messaging (-v) to $0 to see the fin al report." echo " If you believe this message is in error you may use the continue" echo " switch (-continue) to $0 to continue." @@ -5197,15 +5220,6 @@ if [ -z "$QT_QPA_DEFAULT_PLATFORM" ]; then fi fi -# Determine print support plugin belonging to the default QPA platform -if [ "$QT_QPA_DEFAULT_PLATFORM" = "cocoa" ]; then - QT_PRINTSUPPORT_DEFAULT_PLUGIN=cocoaprintersupport -elif [ "$QT_QPA_DEFAULT_PLATFORM" = "windows" ]; then - QT_PRINTSUPPORT_DEFAULT_PLUGIN=windowsprintersupport -elif [ "$QT_QPA_DEFAULT_PLATFORM" = "xcb" ]; then - QT_PRINTSUPPORT_DEFAULT_PLUGIN=cupsprintersupport -fi - if [ -n "$QMAKE_CFLAGS_XCB" ] || [ -n "$QMAKE_LIBS_XCB" ]; then QMakeVar set QMAKE_CFLAGS_XCB "$QMAKE_CFLAGS_XCB" QMakeVar set QMAKE_LIBS_XCB "$QMAKE_LIBS_XCB" @@ -5249,8 +5263,8 @@ if [ "$CFG_FREETYPE" = "auto" ]; then fi # harfbuzz support -[ "$XPLATFORM_MINGW" = "yes" ] && [ "$CFG_HARFBUZZ" = "auto" ] && CFG_HARFBUZZ=no [ "$XPLATFORM_MAC" = "yes" ] && [ "$CFG_HARFBUZZ" = "auto" ] && CFG_HARFBUZZ=yes +[ "$CFG_HARFBUZZ" = "auto" ] && CFG_HARFBUZZ=no # disable auto-detection on non-Mac for now if [ "$CFG_HARFBUZZ" = "auto" ]; then if compileTest unix/harfbuzz "HarfBuzz"; then CFG_HARFBUZZ=system @@ -6165,7 +6179,6 @@ EOF fi echo "#define QT_QPA_DEFAULT_PLATFORM_NAME \"$QT_QPA_DEFAULT_PLATFORM\"" >>"$outpath/src/corelib/global/qconfig.h.new" -echo "#define QT_QPA_DEFAULT_PRINTSUPPORTPLUGIN_NAME \"QT_PRINTSUPPORT_DEFAULT_PLUGIN\"" >>"$outpath/src/corelib/global/qconfig.h.new" # avoid unecessary rebuilds by copying only if qconfig.h has changed if cmp -s "$outpath/src/corelib/global/qconfig.h" "$outpath/src/corelib/global/qconfig.h.new"; then @@ -6235,7 +6248,6 @@ EOF if [ "$CFG_SHARED" = "no" ]; then echo "QT_DEFAULT_QPA_PLUGIN = q$QT_QPA_DEFAULT_PLATFORM" >> "$QTCONFIG.tmp" - echo "QT_DEFAULT_PRINTSUPPORTPLUGIN = $QT_PRINTSUPPORT_DEFAULT_PLUGIN" >> "$QTCONFIG.tmp" echo >> "$QTCONFIG.tmp" fi diff --git a/dist/changes-5.3.0 b/dist/changes-5.3.0 index cb2c3608f0..ae837fc023 100644 --- a/dist/changes-5.3.0 +++ b/dist/changes-5.3.0 @@ -15,6 +15,50 @@ corresponding to tasks in the Qt Bug Tracker: Each of these identifiers can be entered in the bug tracker to obtain more information about a particular change. +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - SIMD support in CPUs: + * [QTBUG-30440] Qt no longer checks for support for the Neon FPU on + ARM platforms at runtime. Code optimized for Neon must be enabled + unconditionally at compile time by ensuring the compiler supports + Neon. You may need to edit your mkspec for that. + + * Qt now automatically generates code for processors supporting SSE2 + on i386 platforms. To disable this, pass the -no-sse2 option during + Qt configuration. Since this feature has been present on CPUs for + 10 years and since Qt no longer checks for runtime support for + SSE2, we strongly encourage users to leave the default setting on + for best performance. + - For Linux distributions that must retain support for CPUs without + SSE2, we recommend doing two builds of Qt and installing the + SSE2-enabled libraries in the LIBDIR/sse2 directory (specially + QtGui, QtQml and QtQuick libraries). Tools, plugins, and examples + are not affected. + - See discussion on the Qt development mailing list: + http://lists.qt-project.org/pipermail/development/2013-November/014085.html + + - SSL and security: + * The default set of ciphers used by QSslSocket has been changed to + exclude ciphers that are using key lengths smaller than 128 + bits. These ciphers are still available and can be enabled by + applications if required. + * [QTBUG-20666] Support for DH and ECDH key exchange cipher suites + when acting as an SSL server has been made possible. This change + means the you can now implement servers that offer forward-secrecy + using Qt. + * Running Qt applications that are setuid is no longer allowed by + default. If you really need to do this then you can call + QCoreApplication::setSetuidAllowed(true) before creating the + QCoreApplication instance. + + - UTF-8 decoding: + * The QString and QTextCodec UTF-8 decoder changed behavior slightly: + when it encounters invalid sequences, it will insert one + replacement character per byte that is invalid, instead of one + replacement character for the whole invalid length. + **************************************************************************** * Platform deprecation notice * **************************************************************************** @@ -24,17 +68,125 @@ information about a particular change. not tested, and most likely has issues that are not fully documented. **************************************************************************** -* Library * +* General * **************************************************************************** -QtWidgets ---------- + - Support for the following platforms has been removed, due to lack of + interest in updating support: INTEGRITY, VxWorks, Solaris on UltraSPARC + (with the Sun Studio compiler suite), AIX on POWER processors (with IBM + Visual Age compiler suite). + - Builtin command-line options such as -reverse, -session, -style + -etc. now all support double dash, e.g. --reverse, --session, + --style... + +**************************************************************************** +* Library * +**************************************************************************** QtCore ------ - Added QSignalBlocker, a RAII-style wrapper around QObject::blockSignals(). + - QLibraryInfo provides information on how Qt was built. + - Added class QMarginsF to support handling margins with floating-point + values. + + - Atomic support: + * Added more operations to the atomic classes, including operator T(), + operator=(T), operator++, operator--. For the QAtomicInteger, + bit-manipulation operations are also provided, both in operator and in + fetchAndXxxYyyyyy modes. + + - Event loop: + * [QTBUG-36611] QCoreApplication::hasPendingEvents and + QAbstractEventDispatcher::hasPendingEvents are now deprecated. Please + refer to the documentation for more information. + + - Logging: + * It is now possible for the qCDebug macros to be used in a printf + style. + * All qCDebug categories are enabled by default, except for Qt's own + categories. + * The logging framework can now be configured with an .ini file. + * Q_LOGGING_CATEGORY and Q_DECLARE_LOGGING_CATEGORY now return a const + object. + + - QByteArray: + * Added NSData/CDataRef converters for QByteArray. + + - QChar: + * Added JoiningType enum and joiningType() method that deprecates the + old QChar::Joining enum and joining() method. + + - QFileSelector: + * [QTBUG-35073] The identifier for OS X has been changed back to + 'osx' from 'mac', and 'mac' and 'darwin' have now been added as + selectors for Darwin OS (which is the base of both OS X and iOS). + + - QHash/QSet: + * Added qHash overloads for float, double and long double. + + - QJsonArray: + * Added convenience methods to QJsonArray for appending QJsonValues + + - QJsonValue: + * Added constructor to QJsonValue for const char * + * QJsonValue::fromVariant() will now convert single-precision Floats + into Doubles instead of Strings + + - QMargins: + * Added missing addition and subtraction operators. + + - QProcess: + * [QTBUG-26136] Added processId() to QProcess. This function will, + unlike pid(), return the actual process identifier on both Windows + and Unix. + + - QRect: + * Added QMargins subtraction operator. + + - QSettings: + * [QTBUG-9824][QTBUG-21062][QTBUG-22745] QSettings now returns the + correct value for isWritable() when using SystemScope settings. + + - QSortFilterProxyModel: + * [QTBUG-30662] Fixed sorting when a previously empty proxy model + becomes populated because of a change in the filter. + + - QStandardPaths: + * [QTBUG-34631] Added QStandardPaths implementation for Android. + + - QString: + * Added QLatin1String overload of contains() + * QString::toUcs4 now does not return invalid UCS-4 code units belonging + to the surrogate range (U+D800 to U+DFFF) when the QString contains + malformed UTF-16 data. Instead, U+FFFD is returned in place of the + malformed subsequence. + + - QTextCodec: + * Encoding a QString in UTF-32 will now replace malformed UTF-16 + subsequences in the string with the Unicode replacement character + (U+FFFD). + + - QVarLengthArray: + * Added the indexOf, lastIndexOf and contains functions to + QVarLengthArray. These functions make the class more similar to + QVector. + + - Windows: + * [QTBUG-35194] Now QStandardPaths::DownloadLocation returns the proper + path for Windows Vista and up + +QtDBus +------ + + - QtDBus adaptors now include the PropertiesChanged signal in + introspection data + + - QDBusServer: + * Added method to QDBusServer to allow anonymous client connections, + even if the connecting client is not authenticated as a user. QtGui ----- @@ -42,12 +194,313 @@ QtGui - Added setSwapInterval() to QSurfaceFormat. Platforms that support setting the swap interval are now defaulting to the value of 1, meaning vsync is enabled. + - [QTBUG-35220] Reading bmp images with alpha channel is now supported + - [QTBUG-36394] The main Embedded Linux platform plugins (eglfs, linuxfb, + kms) are changed to behave identically with regards to terminal keyboard + input: it is turned off by default on all of these platforms. If this + feature is not desired, it can be disabled by setting the environment + variable QT_QPA_ENABLE_TERMINAL_KEYBOARD. + - [QTBUG-36374] Mouse hotplugging is now fully supported in eglfs when + running on Embedded Linux systems with libudev support enabled. + - [QTBUG-36603] Windows Accessibility now handles the disabled state of + widgets correctly. + - Accessibility on Linux now reports the active state correctly. + - [QTBUG-36483] Qt builds on Windows can now be configured for dynamic + loading of the OpenGL implementation. This can be requested by passing + -opengl dynamic to configure. In this mode no modules will link to + opengl32.dll or Angle's libegl/libglesv2. Instead, QtGui will + dynamically choose between desktop and Angle during the first GL/EGL/WGL + call. This allows deploying applications with a single set of Qt + libraries with the ability of transparently falling back to Angle in + case the opengl32.dll is not suitable, due to missing graphics drivers + for example. + - Added class QPageLayout to support handling page layouts including the + page size, orientation and margins. + - [QTBUG-28813][QTBUG-29930][QTBUG-35836] Fixed regression in + arabic text rendering. + - [QTBUG-37332] GLES3 and desktop OpenGL are now fully supported with + EGL + - [QTBUG-36993] Native (that is, not distance field based) text + rendering is now functional on OpenGL 3.2+ core profiles too. + + - Accessibility: + * [QTBUG-37204] Implemented text attributes to enable VoiceOver to read + QTextEdit and QPlainTextEdit. + * Assistive apps such as VoiceOver can now set the focus on widgets + and controls. + + - QColor: + * Exported highly optimized methods for premultiply and unpremultiply of + QRgb values. + + - QFont: + * Added qHash overload for this class. + + - QGuiApplication: + * Restored support for -title command line argument on X11 and added + -qwindowtitle on all platforms. + + - QImage: + * Added rvalue-qualified overloads for mirrored(), rgbSwapped() and + convertToFormat(), allowing in-place conversion in some cases + + - QOpenGLFramebufferObject: + * [QTBUG-35881] Added takeTexture() for retrieving and detaching the + texture from the framebuffer object. + + - QPageSize: + * Added new QPageSize class to implement Adobe Postscript PPD standard + page sizes. This class supports the standard page sizes, names and + keys from the PPD standard, and provides convenient size and rect + conversion methods. + + - QPagedPaintDevice: + * [QTBUG-27685][QTBUG-25744] Paged paint devices such as QPrinter and + QPdfWriter now support all Postscript standard page sizes. + + - QPdfWriter: + * The QPdfWriter now supports setting the PDF orientation, layout and + resolution by using QPageSize and QPageLayout. + + - QTextLayout: + * [QTBUG-18060] Fixed visual cursor movement in bidirectional text. + + - QWindow: + * QWindow::icon() now defaults to the application icon, which can be set + with QGuiApplication::setWindowIcon(). + +QtNetwork +--------- + + - [QTBUG-18714] Added support for the SPDY protocol (version 3.0). + + - QNetworkReply: + * [QTBUG-30880] Added more (specific) HTTP status codes to NetworkError + enum. + + - QSslConfiguration: + * [QTBUG-33208] Added support for the Next Protocol Negotiation (NPN) + TLS extension. + +QtPrintSupport +-------------- + + - [QTBUG-29663] Made the Qt buildsystem automatically include the + necessary plugins so that static applications can print. + - CUPS 1.4 is now required for print support on Linux and other *nix + platforms. + + - QPrintPreviewDialog: + * [QTBUG-36561] Fixed initialization of QPrintPreviewDialog's image + resources for static builds. + + - QPrinter: + * QPrinter can now use QPageSize and QPageLayout in the public api to + control the page layout for a print job. + + - QPrinterInfo: + * [QTBUG-35248] Added new public api for isRemote(), state(), + defaultPageSize(), supportedPageSizes(), supportsCustomPageSizes(), + minimumPhysicalPageSize(), maximumPhysicalPageSize(), + supportedResolutions(), availablePrinterNames(), and + defaultPrinterName(). The use of availablePrinters() is discouraged + due to performance concerns. QtSql ----- - QSqlQuery::isNull(field) now correctly returns true for "no such field". - QSqlQuery::isNull(fieldname) is a new overload. - - QSQLITE: Empty database name now opens in-memory database. - - QSqlError: Now handles alphanumeric error codes. Used by QPSQL. - Old numeric code is deprecated. + - [QTBUG-12186] Fixed the order of values with positional binding in a + QSqlQuery + + - QSQLITE: + * Creating temporary databases is now possible + * Empty database name now opens in-memory database. + + - QSqlError + * Now handles alphanumeric error codes. Used by QPSQL. Old numeric + code is deprecated. + +QtTest +------ + + - Added test duration to xml output. When running tests with xml output a + new tag of the form + is added to each test function and the test as a + whole. + - Added a CSV logging mode that is suitable for importing benchmark + results into spreadsheets. This can be enabled by the -csv option on the + command-line. The CSV logging mode will not print test failures, debug + messages, warnings, etc. + - QtTest now prints an escaped version of QStrings that failed to compare + with QCOMPARE. That is, instead of converting non-printable characters + to question marks, QtTest will print the Unicode representation of the + character in question. + + - Windows: + * [QTBUG-35743] Use correct UTF-8 encoding for XML test results on + platforms with different console encoding. + +QtWidgets +--------- + + - Accessibility: + * Fixed QTextEdit not reporting newlines to accessibility frameworks and + add editable text interface. + + - QAbstractSpinBox: + * [QTBUG-5142] QSpinBox and QDoubleSpinBox widgets can now show the + group (thousands) separators. + + - QColorDialog: + * Ensured QColorDialog::DontUseNativeDialog is respected when showing + the dialog. + + - QDateEdit: + * [QTBUG-36692] Fixed incorrect appearance on OS X of QDateEdit with + calendarPopup enabled. + + - QDrag + * Fixed Drag and Drop driven by touch-synthesized mouse events on + Windows. + + - QListView: + * [QTBUG-4714] Fixed QListView ignoring the grid size for word + wrapping in icon mode + + - QMdiSubWindow: + * [QTBUG-9933][QTBUG-27274] Fixed setWindowFlags() for QMdiSubWindow. + + - QMenu: + * [QTBUG-20094] Enabled sloppy submenu mouse navigation. + * [QTBUG-36142] QMenu now correctly uses text color set by style + sheet for menu items on Windows. + * [QTBUG-36218] Fixed position of menu gutter on Windows when using a + custom widget action. + + - QPlainTextEdit: + * Added find method overload using QRegExp + + - QSpinBox: + * [QTBUG-3032] Fixed keyboard selection with multiple-character strings. + + - QScrollArea: + * [QTBUG-36314] The setting for click position is now respected on OS X. + + - QTextDocument: + * [QTBUG-33336] Added support for empty inline elements in block tags. + + - QTextEdit: + * Added find method overload using QRegExp + + - QWidget: + * [QTBUG-25831] Restored the Qt 4 behavior in the sequence of events + that are delivered to widget windows and their children when a + mouse double click happens: the second MouseButtonPress event from + Qt 5.0-5.2 is no longer sent. + * [QTBUG-33716] QWidgets embedded in QGraphicsProxyWidget are no longer + sent close events when the app is closed on OS X. + * [QTBUG-36178] Fixed an issue where stay-on-top widgets would cover + their own children on OS X. + + - QWizard: + * [QTBUG-7484] Added NoCancelButtonOnLastPage option. + * [QTBUG-36192] Fixed frame when using Vista style/MSVC2012. + + - Text support: + * [QTBUG-36444] Fixed off-by-one in the height of text background. + + - Windows: + * [QTBUG-21371][QTBUG-4397] QWidget::restoreGeometry() now restores + maximized/full screen widgets to the correct screen. + +**************************************************************************** +* Compiler Specific Changes * +**************************************************************************** + + - Variadic macros are now enabled more liberally for gcc, clang, icc. If + you have warnings (because you e.g. compile with -pedantic), disable + them by -Wno-variadic-macros. + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +Android +------- + + - [QTBUG-34781] Fixed regression in "make install" on library projects on + Android so they can be used inside subdirs projects again. + - [QTBUG-36074] Fixed crash on populating large combo boxes or menus. + - [QTBUG-36528] Fixed QDir::entryList() for assets scheme to no longer + skip the first file in the directory. + - [QTBUG-30652] It is now possible to define a splash screen which will be + visible until the first window is created. + - [QTBUG-33704] Sped up first time directory listing in assets by using + pregenerated entry list. + - [QTBUG-37738] Fixed font merging problem which caused e.g. missing + glyphs for Arabic numerals. + - [QTBUG-36025] Fixed a memory leak in the clipboard + + - Fonts: + * [QTBUG-36789] Fixed support for Arabic text. + +Linux +----- + + - Systems with systemd may now pass -journald to configure to send + logging output to journald. Logging will still be sent to stderr for + interactive applications (run from a tty) or with QT_NO_JOURNALD_LOG + set to a non-empty value. + +OS X +---- + + - [QTBUG-18980][QTBUG-38246] Use CoreText text shaping engine for + support of complex scripts. If required, the shaping engine used in + previous versions can be preferred by configuring Qt with + -no-harfbuzz. Alternatively, the QT_HARFBUZZ environment variable + could be set to "old". + +Windows +------- + + - Introduced experimental direct2d platform plugin for Windows. This + plugin shares most code with the current windows plugin, but + substitutes a direct2d-based paint engine for window backing stores + and pixmaps. + + - QtWidgets / QFileDialog: + * Handled the case of having trailing spaces in a filename correctly so + if the filename ends up being empty that the parent path is used + instead. + + - Windows Embedded: + * Fixed building issue when configuring Qt with -qtlibinfix + +X11 / XCB +--------- + + - Qt now supports XInput2 smooth scrolling events + +**************************************************************************** +* Tools * +**************************************************************************** + +moc +--- + + - [QTBUG-33668] Fixed passing -D of a macro defined to something more + complex than a single identifier. + + - QTBUG-36128: + * [QTBUG-36128] Fixed sign conversion warning in generated file. + +qdbus +----- + + - [QTBUG-36524] Fixed a bug that caused the qdbus tool to crash when + trying to display remote interfaces that had complex types without a + matching base Qt type. + diff --git a/doc/global/qt-cpp-defines.qdocconf b/doc/global/qt-cpp-defines.qdocconf index cfd0b07819..300c4402c1 100644 --- a/doc/global/qt-cpp-defines.qdocconf +++ b/doc/global/qt-cpp-defines.qdocconf @@ -19,6 +19,7 @@ defines += Q_QDOC \ Q_COMPILER_RVALUE_REFS Cpp.ignoretokens += \ + ENGINIOCLIENT_EXPORT \ PHONON_EXPORT \ Q_AUTOTEST_EXPORT \ Q_BLUETOOTH_EXPORT \ diff --git a/doc/src/snippets/qx11embedcontainer/main.cpp b/doc/src/snippets/qx11embedcontainer/main.cpp deleted file mode 100644 index 97d6f11385..0000000000 --- a/doc/src/snippets/qx11embedcontainer/main.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -//! [0] -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - - if (app.arguments().count() != 2) { - qFatal("Error - expected executable path as argument"); - return 1; - } - - QX11EmbedContainer container; - container.show(); - - QProcess process(&container); - QString executable(app.arguments()[1]); - QStringList arguments; - arguments << QString::number(container.winId()); - process.start(executable, arguments); - - int status = app.exec(); - process.close(); - return status; -} -//! [0] diff --git a/doc/src/snippets/qx11embedwidget/main.cpp b/doc/src/snippets/qx11embedwidget/main.cpp deleted file mode 100644 index 77b45c1da3..0000000000 --- a/doc/src/snippets/qx11embedwidget/main.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include "embedwidget.h" - -//! [0] -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - - if (app.arguments().count() != 2) { - qFatal("Error - expected window id as argument"); - return 1; - } - - QString windowId(app.arguments()[1]); - EmbedWidget window; - window.embedInto(windowId.toULong()); - window.show(); - - return app.exec(); -} -//! [0] diff --git a/examples/widgets/tutorials/addressbook/part5/addressbook.cpp b/examples/widgets/tutorials/addressbook/part5/addressbook.cpp index ca2f72e9e1..a1005d6912 100644 --- a/examples/widgets/tutorials/addressbook/part5/addressbook.cpp +++ b/examples/widgets/tutorials/addressbook/part5/addressbook.cpp @@ -73,7 +73,7 @@ AddressBook::AddressBook(QWidget *parent) previousButton->setEnabled(false); //! [instantiating FindDialog] - dialog = new FindDialog; + dialog = new FindDialog(this); //! [instantiating FindDialog] connect(addButton, SIGNAL(clicked()), this, SLOT(addContact())); diff --git a/examples/widgets/tutorials/addressbook/part6/addressbook.cpp b/examples/widgets/tutorials/addressbook/part6/addressbook.cpp index 2ced8e2404..536853590b 100644 --- a/examples/widgets/tutorials/addressbook/part6/addressbook.cpp +++ b/examples/widgets/tutorials/addressbook/part6/addressbook.cpp @@ -80,7 +80,7 @@ AddressBook::AddressBook(QWidget *parent) //! [tooltip 2] saveButton->setEnabled(false); - dialog = new FindDialog; + dialog = new FindDialog(this); connect(addButton, SIGNAL(clicked()), this, SLOT(addContact())); connect(submitButton, SIGNAL(clicked()), this, SLOT(submitContact())); diff --git a/examples/widgets/tutorials/addressbook/part7/addressbook.cpp b/examples/widgets/tutorials/addressbook/part7/addressbook.cpp index 2060d97d2f..ba42cd4c93 100644 --- a/examples/widgets/tutorials/addressbook/part7/addressbook.cpp +++ b/examples/widgets/tutorials/addressbook/part7/addressbook.cpp @@ -80,7 +80,7 @@ AddressBook::AddressBook(QWidget *parent) exportButton->setToolTip(tr("Export as vCard")); exportButton->setEnabled(false); - dialog = new FindDialog; + dialog = new FindDialog(this); connect(addButton, SIGNAL(clicked()), this, SLOT(addContact())); connect(submitButton, SIGNAL(clicked()), this, SLOT(submitContact())); diff --git a/mkspecs/android-g++/qmake.conf b/mkspecs/android-g++/qmake.conf index 44624fcca5..78b484fdb5 100644 --- a/mkspecs/android-g++/qmake.conf +++ b/mkspecs/android-g++/qmake.conf @@ -3,7 +3,7 @@ MAKEFILE_GENERATOR = UNIX QMAKE_PLATFORM = android QMAKE_COMPILER = gcc -CONFIG += android_install unversioned_soname android_deployment_settings +CONFIG += android_install unversioned_soname unversioned_libname android_deployment_settings include(../common/linux.conf) include(../common/gcc-base-unix.conf) @@ -26,6 +26,7 @@ contains(QMAKE_HOST.os,Windows) { } else { MINGW_IN_SHELL = 1 QMAKE_DIR_SEP = / + QMAKE_DIRLIST_SEP = : # Because install's ability to set permissions is not relevant on Windows, # and git's msys does not provide it to start with. QMAKE_INSTALL_FILE = cp -f diff --git a/mkspecs/common/qcc-base-qnx.conf b/mkspecs/common/qcc-base-qnx.conf index 0954cfd1ee..a0a88b9605 100644 --- a/mkspecs/common/qcc-base-qnx.conf +++ b/mkspecs/common/qcc-base-qnx.conf @@ -57,4 +57,5 @@ QMAKE_STRIPFLAGS_LIB += --strip-unneeded equals(QMAKE_HOST.os, Windows) { isEmpty(QMAKE_SH): error("This mkspec requires an MSYS environment.") QMAKE_DIR_SEP = / + QMAKE_DIRLIST_SEP = : } diff --git a/mkspecs/common/winrt_winphone/manifests/8.0/WMAppManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/8.0/WMAppManifest.xml.in index 5efb9c7b06..18d37cf7fc 100644 --- a/mkspecs/common/winrt_winphone/manifests/8.0/WMAppManifest.xml.in +++ b/mkspecs/common/winrt_winphone/manifests/8.0/WMAppManifest.xml.in @@ -1,6 +1,6 @@ - + $${WINRT_MANIFEST.languages} $$WINDEPLOYQT_OUTPUT diff --git a/mkspecs/features/win32/windows.prf b/mkspecs/features/win32/windows.prf index 6d8289d949..f19a42b7e2 100644 --- a/mkspecs/features/win32/windows.prf +++ b/mkspecs/features/win32/windows.prf @@ -7,6 +7,8 @@ contains(TEMPLATE, ".*app"){ qt:for(entryLib, $$list($$unique(QMAKE_LIBS_QT_ENTRY))) { isEqual(entryLib, -lqtmain): { + !contains(QMAKE_DEFAULT_LIBDIRS, $$QT.core.libs): \ + QMAKE_LIBS += -L$$QT.core.libs CONFIG(debug, debug|release): QMAKE_LIBS += $${entryLib}$${QT_LIBINFIX}d else: QMAKE_LIBS += $${entryLib}$${QT_LIBINFIX} } else { diff --git a/mkspecs/features/winrt/font_deployment.prf b/mkspecs/features/winrt/font_deployment.prf index 36db5b7cac..c767d5bc1a 100644 --- a/mkspecs/features/winrt/font_deployment.prf +++ b/mkspecs/features/winrt/font_deployment.prf @@ -43,7 +43,7 @@ if(!build_pass:equals(TEMPLATE, "vcapp")) { !isEmpty(FONTS):equals(TEMPLATE, "app") { fonts.files = $$BUILD_DIR/fonts/* - isEmpty($$target.path) { + isEmpty(target.path) { fonts.path = $$OUT_PWD/fonts } else { fonts.path = $$target.path/fonts @@ -54,7 +54,9 @@ if(!build_pass:equals(TEMPLATE, "vcapp")) { } !isEmpty(FONTS):winphone:equals(TEMPLATE, "vcapp"):build_pass { - fonts.files = $$OUT_PWD/fonts/* + for (FONT, FONTS) { + fonts.files += $$OUT_PWD/fonts/$$basename(FONT) + } fonts.path = fonts DEPLOYMENT += fonts } diff --git a/mkspecs/features/winrt/package_manifest.prf b/mkspecs/features/winrt/package_manifest.prf index fda4fb5e8f..444b8b873e 100644 --- a/mkspecs/features/winrt/package_manifest.prf +++ b/mkspecs/features/winrt/package_manifest.prf @@ -27,6 +27,8 @@ # WINRT_MANIFEST.splash_screen: Splash screen image file. Default provided by the mkspec. # WINRT_MANIFEST.iconic_tile_icon: Image file for the "iconic" tile template icon. Default provided by the mkspec. # WINRT_MANIFEST.iconic_tile_small: Image file for the small "iconic" tile template logo. Default provided by the mkspec. +# WINRT_MANIFEST.default_language: Specifies the default language of the application +# WINRT_MANIFEST.languages: Specifies the languages the application supports # 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. @@ -90,10 +92,23 @@ isEmpty(WINRT_MANIFEST.genre): WINRT_MANIFEST.genre = apps.normal 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 winphone: INDENT = "$$escape_expand(\\r\\n) " else: INDENT = "$$escape_expand(\\r\\n) " + # Languages are given as a string list + WINRT_MANIFEST.languages = $$unique(WINRT_MANIFEST.languages) + winphone:equals(WINSDK_VER, 8.0):!isEmpty(WINRT_MANIFEST.languages) { + for(LANGUAGE, WINRT_MANIFEST.languages): \ + MANIFEST_LANGUAGES += "" + + WINRT_MANIFEST.languages = \ + $$join(MANIFEST_LANGUAGES, $$INDENT, \ + "$$escape_expand(\\r\\n) $$INDENT", \ + "$$escape_expand(\\r\\n) ") + } + # Capabilities are given as a string list and may change with the configuration (network, sensors, etc.) WINRT_MANIFEST.capabilities = $$unique(WINRT_MANIFEST.capabilities) WINRT_MANIFEST.capabilities_device = $$unique(WINRT_MANIFEST.capabilities_device) diff --git a/mkspecs/macx-ios-clang/features/default_post.prf b/mkspecs/macx-ios-clang/features/default_post.prf index 496553f8c0..79024c588c 100644 --- a/mkspecs/macx-ios-clang/features/default_post.prf +++ b/mkspecs/macx-ios-clang/features/default_post.prf @@ -77,6 +77,9 @@ equals(TEMPLATE, app) { args += $$system_quote($$arg) system("cd $$system_quote($$OUT_PWD) && $$QMAKE_QMAKE $$args $$system_quote($$_PRO_FILE_) -spec macx-xcode") + check.commands = "$(MAKE) -f $(MAKEFILE).ReleaseSimulator xcode_build_check" + QMAKE_EXTRA_TARGETS += check + } else { load(resolve_config) @@ -113,6 +116,9 @@ equals(TEMPLATE, app) { QMAKE_EXTRA_TARGETS += xcode_build_dir_distclean distclean.depends = xcode_build_dir_distclean QMAKE_EXTRA_TARGETS += distclean + + xcode_build_check.commands = "$(TESTRUNNER) $$title($$cfg)-$${sdk}/$(TARGET).app $(TESTARGS)" + QMAKE_EXTRA_TARGETS += xcode_build_check } CONFIG = diff --git a/mkspecs/qnx-armle-v7-qcc/qplatformdefs.h b/mkspecs/qnx-armle-v7-qcc/qplatformdefs.h index 2f95f0d392..27e4a3aa41 100644 --- a/mkspecs/qnx-armle-v7-qcc/qplatformdefs.h +++ b/mkspecs/qnx-armle-v7-qcc/qplatformdefs.h @@ -83,7 +83,7 @@ #include #define QT_USE_XOPEN_LFS_EXTENSIONS -#if !defined(__EXT_QNX__READDIR64_R) +#if defined(__EXT_QNX__READDIR_R) && !defined(__EXT_QNX__READDIR64_R) #define QT_NO_READDIR64 #endif #include "../common/posix/qplatformdefs.h" diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf index 1ac35611f5..830dde97e9 100644 --- a/mkspecs/win32-g++/qmake.conf +++ b/mkspecs/win32-g++/qmake.conf @@ -93,6 +93,7 @@ QMAKE_LIBS_QT_ENTRY = -lmingw32 -lqtmain !isEmpty(QMAKE_SH) { MINGW_IN_SHELL = 1 QMAKE_DIR_SEP = / + QMAKE_DIRLIST_SEP = : include(../common/shell-unix.conf) # Because install's ability to set permissions is not relevant on Windows, # and git's msys does not provide it to start with. diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 91629ec9dd..2f43c8ad1f 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -2133,6 +2133,16 @@ linked with an application so that they are available as built-in resources. + qmake automatically adds the plugins that are typically needed + by the used Qt modules (see \c QT). + The defaults are tuned towards an optimal out-of-the-box experience. + See \l{Static Plugins} for a list of available plugins, and ways + to override the automatic linking. + + This variable currently has no effect when linking against a + shared/dynamic build of Qt, or when linking libraries. + It may be used for deployment of dynamic plugins at a later time. + \target QT_VERSION_variable \section1 QT_VERSION @@ -2411,6 +2421,9 @@ \li capabilities_device \li Specifies device capabilities to add to the capability list (location, webcam, and so on). This option is not available on Windows Phone. + \row + \li default_language + \li The default language code of the application. Defaults to "en". \row \li dependencies \li Specifies dependencies required by the package. @@ -2437,6 +2450,10 @@ \li identity \li The unique ID of the app. Defaults to reusing the existing generated manifest's UUID, or generates a new UUID if none is present. + \row + \li languages + \li A list of additional language codes supported by the application. This list + is empty by default. \row \li logo_large \li Large logo image file. Default provided by the mkspec. diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index bad4eb5456..0e3e058c7b 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -370,7 +370,8 @@ MakefileGenerator::findFilesInVPATH(ProStringList l, uchar flags, const QString regex.remove(0, dir.length()); } if(real_dir.isEmpty() || exists(real_dir)) { - QStringList files = QDir(real_dir).entryList(QStringList(regex)); + QStringList files = QDir(real_dir).entryList(QStringList(regex), + QDir::NoDotAndDotDot | QDir::AllEntries); if(files.isEmpty()) { debug_msg(1, "%s:%d Failure to find %s in vpath (%s)", __FILE__, __LINE__, @@ -383,8 +384,6 @@ MakefileGenerator::findFilesInVPATH(ProStringList l, uchar flags, const QString l.removeAt(val_it); QString a; for(int i = (int)files.count()-1; i >= 0; i--) { - if(files[i] == "." || files[i] == "..") - continue; a = real_dir + files[i]; if(!(flags & VPATH_NoFixify)) a = fileFixify(a); @@ -1324,7 +1323,8 @@ MakefileGenerator::writeInstalls(QTextStream &t, bool noBuild) continue; } QString local_dirstr = Option::fixPathToLocalOS(dirstr, true); - QStringList files = QDir(local_dirstr).entryList(QStringList(filestr)); + QStringList files = QDir(local_dirstr).entryList(QStringList(filestr), + QDir::NoDotAndDotDot | QDir::AllEntries); if (installConfigValues.contains("no_check_exist") && files.isEmpty()) { QString dst_file = filePrefixRoot(root, dst_dir); QString cmd; @@ -1346,8 +1346,6 @@ MakefileGenerator::writeInstalls(QTextStream &t, bool noBuild) } for(int x = 0; x < files.count(); x++) { QString file = files[x]; - if(file == "." || file == "..") //blah - continue; uninst.append(rm_dir_contents + " " + escapeFilePath(filePrefixRoot(root, fileFixify(dst_dir + file, FileFixifyAbsolute, false)))); QFileInfo fi(fileInfo(dirstr + file)); QString dst_file = filePrefixRoot(root, fileFixify(dst_dir, FileFixifyAbsolute, false)); @@ -3217,7 +3215,7 @@ MakefileGenerator::writePkgConfigFile() QString prefix = pkgConfigPrefix(); QString libDir = project->first("QMAKE_PKGCONFIG_LIBDIR").toQString(); if(libDir.isEmpty()) - libDir = prefix + Option::dir_sep + "lib" + Option::dir_sep; + libDir = prefix + "/lib"; QString includeDir = project->first("QMAKE_PKGCONFIG_INCDIR").toQString(); if(includeDir.isEmpty()) includeDir = prefix + "/include"; @@ -3284,10 +3282,12 @@ MakefileGenerator::writePkgConfigFile() // libs t << "Libs: "; - QString pkgConfiglibDir; QString pkgConfiglibName; if (target_mode == TARG_MAC_MODE && project->isActiveConfig("lib_bundle")) { - pkgConfiglibDir = "-F${libdir}"; + if (libDir != QLatin1String("/System/Library/Frameworks") + && libDir != QLatin1String("/Library/Frameworks")) { + t << "-F${libdir} "; + } ProString bundle; if (!project->isEmpty("QMAKE_FRAMEWORK_BUNDLE_NAME")) bundle = unescapeFilePath(project->first("QMAKE_FRAMEWORK_BUNDLE_NAME")); @@ -3298,12 +3298,13 @@ MakefileGenerator::writePkgConfigFile() bundle = bundle.left(suffix); pkgConfiglibName = "-framework " + bundle + " "; } else { - pkgConfiglibDir = "-L${libdir}"; + if (!project->values("QMAKE_DEFAULT_LIBDIRS").contains(libDir)) + t << "-L${libdir} "; pkgConfiglibName = "-l" + unescapeFilePath(project->first("QMAKE_ORIG_TARGET")); if (project->isActiveConfig("shared")) pkgConfiglibName += project->first("TARGET_VERSION_EXT").toQString(); } - t << pkgConfiglibDir << " " << pkgConfiglibName << " \n"; + t << pkgConfiglibName << " \n"; ProStringList libs; if(!project->isEmpty("QMAKE_INTERNAL_PRL_LIBS")) { @@ -3327,7 +3328,10 @@ MakefileGenerator::writePkgConfigFile() << varGlue("PRL_EXPORT_CXXFLAGS", "", " ", " ") << varGlue("QMAKE_PKGCONFIG_CFLAGS", "", " ", " ") // << varGlue("DEFINES","-D"," -D"," ") - << "-I${includedir}\n"; + ; + if (!project->values("QMAKE_DEFAULT_INCDIRS").contains(includeDir)) + t << "-I${includedir}"; + t << endl; // requires const QString requires = project->values("QMAKE_PKGCONFIG_REQUIRES").join(' '); diff --git a/qmake/generators/projectgenerator.cpp b/qmake/generators/projectgenerator.cpp index 3cd5a22a33..05fdcb320d 100644 --- a/qmake/generators/projectgenerator.cpp +++ b/qmake/generators/projectgenerator.cpp @@ -111,10 +111,8 @@ ProjectGenerator::init() dir += Option::dir_sep; if (Option::recursive) { QStringList files = QDir(dir).entryList(QDir::Files); - for(int i = 0; i < (int)files.count(); i++) { - if(files[i] != "." && files[i] != "..") - dirs.append(dir + files[i] + QDir::separator() + builtin_regex); - } + for (int i = 0; i < files.count(); i++) + dirs.append(dir + files[i] + QDir::separator() + builtin_regex); } regex = builtin_regex; } else { @@ -137,12 +135,9 @@ ProjectGenerator::init() regex = regex.right(regex.length() - (s+1)); } if (Option::recursive) { - QStringList entries = QDir(dir).entryList(QDir::Dirs); - for(int i = 0; i < (int)entries.count(); i++) { - if(entries[i] != "." && entries[i] != "..") { - dirs.append(dir + entries[i] + QDir::separator() + regex); - } - } + QStringList entries = QDir(dir).entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (int i = 0; i < entries.count(); i++) + dirs.append(dir + entries[i] + QDir::separator() + regex); } QStringList files = QDir(dir).entryList(QDir::nameFiltersFromString(regex)); for(int i = 0; i < (int)files.count(); i++) { @@ -186,16 +181,15 @@ ProjectGenerator::init() nd += QDir::separator(); nd += profiles[i]; fileFixify(nd); - if(profiles[i] != "." && profiles[i] != ".." && - !subdirs.contains(nd, Qt::CaseInsensitive) && !out_file.endsWith(nd)) + if (!subdirs.contains(nd, Qt::CaseInsensitive) && !out_file.endsWith(nd)) subdirs.append(nd); } } if (Option::recursive) { - QStringList dirs = QDir(newdir).entryList(QDir::Dirs); + QStringList dirs = QDir(newdir).entryList(QDir::Dirs | QDir::NoDotAndDotDot); for(int i = 0; i < (int)dirs.count(); i++) { QString nd = fileFixify(newdir + QDir::separator() + dirs[i]); - if(dirs[i] != "." && dirs[i] != ".." && !knownDirs.contains(nd, Qt::CaseInsensitive)) + if (!knownDirs.contains(nd, Qt::CaseInsensitive)) knownDirs.append(nd); } } @@ -207,12 +201,13 @@ ProjectGenerator::init() dir = regx.left(s+1); regx = regx.right(regx.length() - (s+1)); } - QStringList files = QDir(dir).entryList(QDir::nameFiltersFromString(regx), QDir::Dirs); + QStringList files = QDir(dir).entryList(QDir::nameFiltersFromString(regx), + QDir::Dirs | QDir::NoDotAndDotDot); ProStringList &subdirs = v["SUBDIRS"]; for(int i = 0; i < (int)files.count(); i++) { QString newdir(dir + files[i]); QFileInfo fi(fileInfo(newdir)); - if(fi.fileName() != "." && fi.fileName() != "..") { + { newdir = fileFixify(newdir); if(exists(fi.filePath() + QDir::separator() + fi.fileName() + Option::pro_ext) && !subdirs.contains(newdir)) { diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 4c3df4efe8..5ea47cc867 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -749,7 +749,9 @@ UnixMakefileGenerator::defaultInstall(const QString &t) target = "$(QMAKE_TARGET)"; } else if(project->first("TEMPLATE") == "lib") { if(project->isEmpty("QMAKE_CYGWIN_SHLIB")) { - if(!project->isActiveConfig("staticlib") && !project->isActiveConfig("plugin")) { + if (!project->isActiveConfig("staticlib") + && !project->isActiveConfig("plugin") + && !project->isActiveConfig("unversioned_libname")) { if(project->isEmpty("QMAKE_HPUX_SHLIB")) { links << "$(TARGET0)" << "$(TARGET1)" << "$(TARGET2)"; } else { diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 6e08c138ed..a28760015e 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -234,14 +234,15 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) if(!project->isEmpty("QMAKE_BUNDLE")) { t << "TARGETD = " << escapeFilePath(var("TARGET_x.y")) << endl; t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl; - } else if(project->isEmpty("QMAKE_HPUX_SHLIB")) { - t << "TARGETD = " << escapeFilePath(var("TARGET_x.y.z")) << endl; - t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl; - t << "TARGET1 = " << escapeFilePath(var("TARGET_x")) << endl; - t << "TARGET2 = " << escapeFilePath(var("TARGET_x.y")) << endl; - } else { - t << "TARGETD = " << escapeFilePath(var("TARGET_x")) << endl; + } else if (!project->isActiveConfig("unversioned_libname")) { t << "TARGET0 = " << escapeFilePath(var("TARGET_")) << endl; + if (project->isEmpty("QMAKE_HPUX_SHLIB")) { + t << "TARGETD = " << escapeFilePath(var("TARGET_x.y.z")) << endl; + t << "TARGET1 = " << escapeFilePath(var("TARGET_x")) << endl; + t << "TARGET2 = " << escapeFilePath(var("TARGET_x.y")) << endl; + } else { + t << "TARGETD = " << escapeFilePath(var("TARGET_x")) << endl; + } } } writeExtraCompilerVariables(t); @@ -574,22 +575,36 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) t << "\n\t" << var("QMAKE_POST_LINK"); t << endl << endl; } else if(project->isEmpty("QMAKE_HPUX_SHLIB")) { - t << "\n\t" - << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2)\n\t" - << var("QMAKE_LINK_SHLIB_CMD") << "\n\t"; - t << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET0)") << "\n\t" - << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET1)") << "\n\t" - << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET2)"); - if(!destdir.isEmpty()) + t << "\n\t"; + + if (!project->isActiveConfig("unversioned_libname")) + t << "-$(DEL_FILE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2)"; + else + t << "-$(DEL_FILE) $(TARGET)"; + + t << "\n\t" << var("QMAKE_LINK_SHLIB_CMD"); + + if (!project->isActiveConfig("unversioned_libname")) { + t << "\n\t" + << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET0)") << "\n\t" + << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET1)") << "\n\t" + << varGlue("QMAKE_LN_SHLIB","-"," "," $(TARGET) $(TARGET2)"); + } + if (!destdir.isEmpty()) { t << "\n\t" << "-$(DEL_FILE) " << destdir << "$(TARGET)\n\t" - << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t" - << "-$(DEL_FILE) " << destdir << "$(TARGET1)\n\t" - << "-$(DEL_FILE) " << destdir << "$(TARGET2)\n\t" - << "-$(MOVE) $(TARGET) " << destdir << " \n\t" - << "-$(MOVE) $(TARGET0) " << destdir << " \n\t" - << "-$(MOVE) $(TARGET1) " << destdir << " \n\t" - << "-$(MOVE) $(TARGET2) " << destdir << " \n\t"; + << "-$(MOVE) $(TARGET) " << destdir << " "; + + if (!project->isActiveConfig("unversioned_libname")) { + t << "\n\t" + << "-$(DEL_FILE) " << destdir << "$(TARGET0)\n\t" + << "-$(DEL_FILE) " << destdir << "$(TARGET1)\n\t" + << "-$(DEL_FILE) " << destdir << "$(TARGET2)\n\t" + << "-$(MOVE) $(TARGET0) " << destdir << " \n\t" + << "-$(MOVE) $(TARGET1) " << destdir << " \n\t" + << "-$(MOVE) $(TARGET2) " << destdir << " "; + } + } if(!project->isEmpty("QMAKE_POST_LINK")) t << "\n\t" << var("QMAKE_POST_LINK"); t << endl << endl; @@ -924,8 +939,12 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) } else if(!project->isActiveConfig("staticlib") && project->values("QMAKE_APP_FLAG").isEmpty() && !project->isActiveConfig("plugin")) { t << "\t-$(DEL_FILE) " << destdir << "$(TARGET) \n"; - t << "\t-$(DEL_FILE) " << destdir << "$(TARGET0) " << destdir << "$(TARGET1) " - << destdir << "$(TARGET2) $(TARGETA)\n"; + if (!project->isActiveConfig("unversioned_libname")) { + t << "\t-$(DEL_FILE) " << destdir << "$(TARGET0) " << destdir << "$(TARGET1) " + << destdir << "$(TARGET2) $(TARGETA)\n"; + } else { + t << "\t-$(DEL_FILE) $(TARGETA)\n"; + } } else { t << "\t-$(DEL_FILE) " << destdir << "$(TARGET) \n"; } @@ -1165,7 +1184,10 @@ void UnixMakefileGenerator::init2() project->first("VER_MIN") + "." + project->first("VER_PAT")); } - project->values("TARGET") = project->values("TARGET_x.y.z"); + if (project->isActiveConfig("unversioned_libname")) + project->values("TARGET") = project->values("TARGET_"); + else + project->values("TARGET") = project->values("TARGET_x.y.z"); } if(project->isEmpty("QMAKE_LN_SHLIB")) project->values("QMAKE_LN_SHLIB").append("ln -s"); diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index ac258e2841..2bd3301e16 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -397,8 +397,8 @@ QString VcprojGenerator::retrievePlatformToolSet() const return envVar; QString suffix; - if (vcProject.Configuration.WinPhone) - suffix = "_wp80"; + if (project->isActiveConfig("winphone")) + suffix = '_' + project->first("WINTARGET_VER").toQString().toLower(); else if (project->first("QMAKE_TARGET_OS") == "xp") suffix = "_xp"; diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index 5ae99bab92..7896688e54 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -1064,10 +1064,18 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( evalError(fL1S("shell_path(path) requires one argument.")); } else { QString rstr = args.at(0).toQString(m_tmp1); - if (m_dirSep.startsWith(QLatin1Char('\\'))) + if (m_dirSep.startsWith(QLatin1Char('\\'))) { rstr.replace(QLatin1Char('/'), QLatin1Char('\\')); - else + } else { rstr.replace(QLatin1Char('\\'), QLatin1Char('/')); +#ifdef Q_OS_WIN + // Convert d:/foo/bar to msys-style /d/foo/bar. + if (rstr.length() > 2 && rstr.at(1) == QLatin1Char(':') && rstr.at(2) == QLatin1Char('/')) { + rstr[1] = rstr.at(0); + rstr[0] = QLatin1Char('/'); + } +#endif + } ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0))); } break; diff --git a/qmake/option.cpp b/qmake/option.cpp index a2bd938666..677899950c 100644 --- a/qmake/option.cpp +++ b/qmake/option.cpp @@ -488,7 +488,7 @@ bool Option::postProcessProject(QMakeProject *project) Option::dir_sep = project->dirSep().toQString(); - if (Option::output_dir.startsWith(project->buildRoot())) + if (!project->buildRoot().isEmpty() && Option::output_dir.startsWith(project->buildRoot())) Option::mkfile::cachefile_depth = Option::output_dir.mid(project->buildRoot().length()).count('/'); diff --git a/qtbase.pro b/qtbase.pro index ed6fc394cb..d6861cf09f 100644 --- a/qtbase.pro +++ b/qtbase.pro @@ -87,7 +87,7 @@ INSTALLS += syncqt # qtPrepareTool() to find the non-installed syncqt. prefix_build|!equals(PWD, $$OUT_PWD) { - cmd = perl -w $$shell_path($$PWD/bin/syncqt.pl) + cmd = perl -w $$system_path($$PWD/bin/syncqt.pl) TOOL_PRI = $$OUT_PWD/mkspecs/modules/qt_tool_syncqt.pri diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp index 2de477b3bc..e70727c65e 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp @@ -40,6 +40,13 @@ #include "libEGL/Display.h" +#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) +# include +# include +# include +typedef ABI::Windows::Foundation::IEventHandler SuspendEventHandler; +#endif + #ifdef _DEBUG // this flag enables suppressing some spurious warnings that pop up in certain WebGL samples // and conformance tests. to enable all warnings, remove this define. @@ -426,9 +433,49 @@ EGLint Renderer11::initialize() } } +#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) + // Monitor when the application suspends so that Trim() can be called + Microsoft::WRL::ComPtr application; + result = RoGetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&application)); + if (FAILED(result)) + { + ERR("Error obtaining CoreApplication: 0x%08X", result); + return EGL_NOT_INITIALIZED; + } + + EventRegistrationToken cookie; + result = application->add_Suspending(Microsoft::WRL::Callback(this, &Renderer11::onSuspend).Get(), &cookie); + if (FAILED(result)) + { + ERR("Error setting suspend callback: 0x%08X", result); + return EGL_NOT_INITIALIZED; + } +#endif + return EGL_SUCCESS; } +#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) +HRESULT Renderer11::onSuspend(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *) +{ + if (!mDevice) + return S_OK; + + Microsoft::WRL::ComPtr dxgiDevice; + HRESULT result = mDevice->QueryInterface(IID_PPV_ARGS(&dxgiDevice)); + if (FAILED(result)) + { + ERR("Error obtaining DXGIDevice3 on suspend: 0x%08X", result); + return S_OK; + } + + dxgiDevice->Trim(); + + return S_OK; +} +#endif + // do any one-time device initialization // NOTE: this is also needed after a device lost/reset // to reset the scene status and ensure the default states are reset. diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h index a8a722c56c..773fc26db1 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h @@ -18,6 +18,17 @@ #include "libGLESv2/renderer/d3d11/InputLayoutCache.h" #include "libGLESv2/renderer/RenderTarget.h" +#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) +struct IInspectable; +namespace ABI { + namespace Windows { + namespace ApplicationModel { + struct ISuspendingEventArgs; + } + } +} +#endif + namespace gl { class Renderbuffer; @@ -202,6 +213,10 @@ class Renderer11 : public Renderer RenderTarget *drawRenderTarget, bool wholeBufferCopy); ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); +#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) + HRESULT onSuspend(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); +#endif + HMODULE mD3d11Module; HMODULE mDxgiModule; diff --git a/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro b/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro index 7d997d7d8b..d505c30aa6 100644 --- a/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro +++ b/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro @@ -7,6 +7,9 @@ CONFIG += \ exceptions_off rtti_off CONFIG -= qt +contains(QT_CONFIG, debug_and_release):CONFIG += debug_and_release +contains(QT_CONFIG, build_all):CONFIG += build_all + DESTDIR = $$QT_BUILD_TREE/lib DEFINES += HAVE_CONFIG_H diff --git a/src/angle/patches/0016-ANGLE-WinRT-Call-Trim-when-application-suspends.patch b/src/angle/patches/0016-ANGLE-WinRT-Call-Trim-when-application-suspends.patch new file mode 100644 index 0000000000..bf2a1ad363 --- /dev/null +++ b/src/angle/patches/0016-ANGLE-WinRT-Call-Trim-when-application-suspends.patch @@ -0,0 +1,118 @@ +From 158b7642c53843ed954fa667ff23b8746f95f8eb Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Tue, 22 Apr 2014 09:13:57 +0300 +Subject: [PATCH] ANGLE WinRT: Call Trim() when application suspends + +This is required by Windows Store Apps to pass certification. + +Task-number: QTBUG-38481 +Change-Id: I6dc00431ee5f6c7d4c64111ccc38f46483d3b9a8 +--- + .../src/libGLESv2/renderer/d3d11/Renderer11.cpp | 47 ++++++++++++++++++++++ + .../src/libGLESv2/renderer/d3d11/Renderer11.h | 15 +++++++ + 2 files changed, 62 insertions(+) + +diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp +index 2de477b..e70727c 100644 +--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.cpp +@@ -40,6 +40,13 @@ + + #include "libEGL/Display.h" + ++#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) ++# include ++# include ++# include ++typedef ABI::Windows::Foundation::IEventHandler SuspendEventHandler; ++#endif ++ + #ifdef _DEBUG + // this flag enables suppressing some spurious warnings that pop up in certain WebGL samples + // and conformance tests. to enable all warnings, remove this define. +@@ -426,9 +433,49 @@ EGLint Renderer11::initialize() + } + } + ++#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) ++ // Monitor when the application suspends so that Trim() can be called ++ Microsoft::WRL::ComPtr application; ++ result = RoGetActivationFactory(Microsoft::WRL::Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), ++ IID_PPV_ARGS(&application)); ++ if (FAILED(result)) ++ { ++ ERR("Error obtaining CoreApplication: 0x%08X", result); ++ return EGL_NOT_INITIALIZED; ++ } ++ ++ EventRegistrationToken cookie; ++ result = application->add_Suspending(Microsoft::WRL::Callback(this, &Renderer11::onSuspend).Get(), &cookie); ++ if (FAILED(result)) ++ { ++ ERR("Error setting suspend callback: 0x%08X", result); ++ return EGL_NOT_INITIALIZED; ++ } ++#endif ++ + return EGL_SUCCESS; + } + ++#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) ++HRESULT Renderer11::onSuspend(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *) ++{ ++ if (!mDevice) ++ return S_OK; ++ ++ Microsoft::WRL::ComPtr dxgiDevice; ++ HRESULT result = mDevice->QueryInterface(IID_PPV_ARGS(&dxgiDevice)); ++ if (FAILED(result)) ++ { ++ ERR("Error obtaining DXGIDevice3 on suspend: 0x%08X", result); ++ return S_OK; ++ } ++ ++ dxgiDevice->Trim(); ++ ++ return S_OK; ++} ++#endif ++ + // do any one-time device initialization + // NOTE: this is also needed after a device lost/reset + // to reset the scene status and ensure the default states are reset. +diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h +index a8a722c..773fc26 100644 +--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h ++++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d11/Renderer11.h +@@ -18,6 +18,17 @@ + #include "libGLESv2/renderer/d3d11/InputLayoutCache.h" + #include "libGLESv2/renderer/RenderTarget.h" + ++#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) ++struct IInspectable; ++namespace ABI { ++ namespace Windows { ++ namespace ApplicationModel { ++ struct ISuspendingEventArgs; ++ } ++ } ++} ++#endif ++ + namespace gl + { + class Renderbuffer; +@@ -202,6 +213,10 @@ class Renderer11 : public Renderer + RenderTarget *drawRenderTarget, bool wholeBufferCopy); + ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); + ++#if defined(ANGLE_OS_WINRT) && !defined(ANGLE_OS_WINPHONE) ++ HRESULT onSuspend(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); ++#endif ++ + HMODULE mD3d11Module; + HMODULE mDxgiModule; + +-- +1.9.0.msysgit.0 + diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index f7bb1e91bd..95d7713cfe 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -253,8 +253,9 @@ QUnifiedTimer *QUnifiedTimer::instance() void QUnifiedTimer::maybeUpdateAnimationsToCurrentTime() { - if (time.elapsed() - lastTick > 50) - updateAnimationTimers(driver->elapsed()); + qint64 elapsed = driver->elapsed(); + if (elapsed - lastTick > 50) + updateAnimationTimers(elapsed); } void QUnifiedTimer::updateAnimationTimers(qint64 currentTick) @@ -263,7 +264,7 @@ void QUnifiedTimer::updateAnimationTimers(qint64 currentTick) if(insideTick) return; - qint64 totalElapsed = currentTick >= 0 ? currentTick : time.elapsed(); + qint64 totalElapsed = currentTick >= 0 ? currentTick : driver->elapsed(); // ignore consistentTiming in case the pause timer is active qint64 delta = (consistentTiming && !pauseTimer.isActive()) ? diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp index 54312601e4..072cda63aa 100644 --- a/src/corelib/codecs/qutfcodec.cpp +++ b/src/corelib/codecs/qutfcodec.cpp @@ -52,6 +52,8 @@ QT_BEGIN_NAMESPACE enum { Endian = 0, Data = 1 }; +static const uchar utf8bom[] = { 0xef, 0xbb, 0xbf }; + #if defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSE2) static inline bool simdEncodeAscii(uchar *&dst, const ushort *&nextAscii, const ushort *&src, const ushort *end) { @@ -187,9 +189,9 @@ QByteArray QUtf8::convertFromUnicode(const QChar *uc, int len, QTextCodec::Conve int invalid = 0; if (state && !(state->flags & QTextCodec::IgnoreHeader)) { // append UTF-8 BOM - *cursor++ = 0xef; - *cursor++ = 0xbb; - *cursor++ = 0xbf; + *cursor++ = utf8bom[0]; + *cursor++ = utf8bom[1]; + *cursor++ = utf8bom[2]; } const ushort *nextAscii = src; @@ -240,19 +242,31 @@ QString QUtf8::convertToUnicode(const char *chars, int len) const uchar *src = reinterpret_cast(chars); const uchar *end = src + len; - while (src < end) { - const uchar *nextAscii = end; - if (simdDecodeAscii(dst, nextAscii, src, end)) - break; + // attempt to do a full decoding in SIMD + const uchar *nextAscii = end; + if (!simdDecodeAscii(dst, nextAscii, src, end)) { + // at least one non-ASCII entry + // check if we failed to decode the UTF-8 BOM; if so, skip it + if (Q_UNLIKELY(src == reinterpret_cast(chars)) + && end - src >= 3 + && Q_UNLIKELY(src[0] == utf8bom[0] && src[1] == utf8bom[1] && src[2] == utf8bom[2])) { + src += 3; + } - do { - uchar b = *src++; - int res = QUtf8Functions::fromUtf8(b, dst, src, end); - if (res < 0) { - // decoding error - *dst++ = QChar::ReplacementCharacter; - } - } while (src < nextAscii); + while (src < end) { + nextAscii = end; + if (simdDecodeAscii(dst, nextAscii, src, end)) + break; + + do { + uchar b = *src++; + int res = QUtf8Functions::fromUtf8(b, dst, src, end); + if (res < 0) { + // decoding error + *dst++ = QChar::ReplacementCharacter; + } + } while (src < nextAscii); + } } result.truncate(dst - reinterpret_cast(result.constData())); diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf index 18342d0138..c8eb15a7f7 100644 --- a/src/corelib/doc/qtcore.qdocconf +++ b/src/corelib/doc/qtcore.qdocconf @@ -26,7 +26,7 @@ qhp.QtCore.subprojects.classes.sortPages = true tagfile = ../../../doc/qtcore/qtcore.tags -depends += qtgui qtwidgets qtnetwork qtdoc qtmacextras qtquick qtlinguist qtdesigner qtconcurrent qtxml qmake +depends += activeqt qtdbus qtgui qtwidgets qtnetwork qtdoc qtmacextras qtqml qtquick qtlinguist qtdesigner qtconcurrent qtxml qmake headerdirs += .. diff --git a/src/corelib/doc/snippets/code/doc_src_plugins-howto.pro b/src/corelib/doc/snippets/code/doc_src_plugins-howto.pro index 5eb9604ed7..dc75c1d9d7 100644 --- a/src/corelib/doc/snippets/code/doc_src_plugins-howto.pro +++ b/src/corelib/doc/snippets/code/doc_src_plugins-howto.pro @@ -43,7 +43,7 @@ CONFIG += release #! [3] #! [4] -CONFIG += qpa_minimal_plugin +QTPLUGIN.platforms = qminimal #! [4] #! [5] @@ -53,7 +53,7 @@ QTPLUGIN += qjpeg \ #! [5] #! [6] -CONFIG -= import_qpa_plugin +QTPLUGIN.platforms = - #! [6] #! [7] diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qregexp.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qregexp.cpp index 779fbaa723..530819a173 100644 --- a/src/corelib/doc/snippets/code/src_corelib_tools_qregexp.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_tools_qregexp.cpp @@ -77,7 +77,7 @@ QRegExp mark("\\b" // word boundary QRegExp rx("^\\d\\d?$"); // match integers 0 to 99 rx.indexIn("123"); // returns -1 (no match) rx.indexIn("-6"); // returns -1 (no match) -rx.indexIn("6"); // returns 0 (matched as position 0) +rx.indexIn("6"); // returns 0 (matched at position 0) //! [4] diff --git a/src/corelib/doc/src/plugins-howto.qdoc b/src/corelib/doc/src/plugins-howto.qdoc index 7565d610cc..7dc0d01cce 100644 --- a/src/corelib/doc/src/plugins-howto.qdoc +++ b/src/corelib/doc/src/plugins-howto.qdoc @@ -234,7 +234,7 @@ application is to compile it into a dynamic library that is shipped separately, and detected and loaded at runtime. - Plugins can be linked statically against your application. If you + Plugins can be linked statically into your application. If you build the static version of Qt, this is the only option for including Qt's predefined plugins. Using static plugins makes the deployment less error-prone, but has the disadvantage that no @@ -253,7 +253,8 @@ \row \li \c qico \li Image formats \li ICO \row \li \c qsvg \li Image formats \li SVG \row \li \c qtiff \li Image formats \li TIFF - \row \li \c qsqldb2 \li SQL driver \li IBM DB2 \row \li \c qsqlibase \li SQL driver \li Borland InterBase + \row \li \c qsqldb2 \li SQL driver \li IBM DB2 + \row \li \c qsqlibase \li SQL driver \li Borland InterBase \row \li \c qsqlite \li SQL driver \li SQLite version 3 \row \li \c qsqlite2 \li SQL driver \li SQLite version 2 \row \li \c qsqlmysql \li SQL driver \li MySQL @@ -263,22 +264,48 @@ \row \li \c qsqltds \li SQL driver \li Sybase Adaptive Server (TDS) \endtable - To link statically against those plugins, you need to add + To link those plugins statically, you need to add the required plugins to your build using \c QTPLUGIN. - Q_IMPORT_PLUGIN() macros are also needed in application code, - but those are automatically generated by qmake and added to - your application project. In the \c .pro file for your application, you need the following entry: \snippet code/doc_src_plugins-howto.pro 5 + qmake automatically adds the plugins to QTPLUGIN that are typically + needed by the used Qt modules (see \c QT), while more specialized + plugins need to be added manually. + The default list of automatically added plugins can be overridden + per type. + For example, to link the minimal plugin instead of the default Qt + platform adaptation plugin, use: + + \snippet code/doc_src_plugins-howto.pro 4 + + If you want neither the default nor the minimal QPA plugin to be + linked automatically, use: + + \snippet code/doc_src_plugins-howto.pro 6 + + The defaults are tuned towards an optimal out-of-the-box experience, + but may unnecessarily bloat the application. + It is recommended to inspect the linker command line built by qmake + and eliminate unnecessary plugins. + + \section2 Details of Linking Static Plugins + + To cause static plugins actually being linked and instantiated, + Q_IMPORT_PLUGIN() macros are also needed in application code, + but those are automatically generated by qmake and added to + your application project. + If you do not want all plugins added to QTPLUGIN to be automatically linked, remove \c import_plugins from the \c CONFIG variable: \snippet code/doc_src_plugins-howto.pro 7 + \section2 Creating Static Plugins + It is also possible to create your own static plugins, by following these steps: @@ -297,17 +324,6 @@ to make sure that the \c{QT_STATICPLUGIN} preprocessor macro is defined. - The default Qt platform adaptation plugin is automatically added to QTPLUGIN - in static builds. If you want to add the minimal plugin instead, add \c qpa_minimal_plugin - to \c CONFIG: - - \snippet code/doc_src_plugins-howto.pro 4 - - If you want neither the default nor the minimal QPA plugin to be linked automatically, - remove \c import_qpa_plugin from \c CONFIG: - - \snippet code/doc_src_plugins-howto.pro 6 - \section1 Deploying and Debugging Plugins The \l{Deploying Plugins} document covers the process of deploying diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index b62ae30fc5..bb892cf751 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -844,21 +844,28 @@ #endif /* Q_CC_MSVC */ #ifdef __cplusplus +# include # if defined(Q_OS_QNX) -# include # if defined(_YVALS) || defined(_LIBCPP_VER) // QNX: libcpp (Dinkumware-based) doesn't have the // header, so the feature is useless, even if the compiler supports // it. Disable. -# ifdef Q_COMPILER_INITIALIZER_LISTS -# undef Q_COMPILER_INITIALIZER_LISTS -# endif -# ifdef Q_COMPILER_RVALUE_REFS -# undef Q_COMPILER_RVALUE_REFS -# endif +# undef Q_COMPILER_INITIALIZER_LISTS +// That libcpp doesn't have std::move either, so disable everything +// related to rvalue refs. +# undef Q_COMPILER_RVALUE_REFS +# undef Q_COMPILER_REF_QUALIFIERS # endif +# endif // Q_OS_QNX +# if (defined(Q_CC_CLANG) || defined(Q_CC_INTEL)) && defined(Q_OS_MAC) && defined(__GNUC_LIBSTD__) \ + && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) +// Mac OS X: Apple has not updated libstdc++ since 2007, which means it does not have +// or std::move. Let's disable these features +# undef Q_COMPILER_INITIALIZER_LISTS +# undef Q_COMPILER_RVALUE_REFS +# undef Q_COMPILER_REF_QUALIFIERS # endif -#endif // Q_OS_QNX +#endif /* * C++11 keywords and expressions diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 3832e70c94..a9621e744c 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -58,7 +58,10 @@ #if !defined(QT_BUILD_QMAKE) && !defined(QT_BUILD_CONFIGURE) #include #include +#endif #define QT_SUPPORTS(FEATURE) (!defined(QT_NO_##FEATURE)) +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) +# define QT_NO_UNSHARABLE_CONTAINERS #endif /* These two macros makes it possible to turn the builtin line expander into a diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index da26490d18..4a602e4b2b 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1207,6 +1207,23 @@ static void android_default_message_handler(QtMsgType type, static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf) { + // to determine logging destination and marking logging environment variable as deprecated + // ### remove when deprecated + struct LogDestination { + LogDestination(const char *deprecated, bool forceConsole) { + const char* replacement = "QT_LOGGING_TO_CONSOLE"; + bool newEnv = qEnvironmentVariableIsSet(replacement); + bool oldEnv = qEnvironmentVariableIsSet(deprecated); + if (oldEnv && !newEnv && !forceConsole) { + fprintf(stderr, "Warning: Environment variable %s is deprecated, " + "use %s instead.\n", deprecated, replacement); + fflush(stderr); + } + toConsole = newEnv || oldEnv || forceConsole; + } + bool toConsole; + }; + QString logMessage = qMessageFormatString(type, context, buf); #if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB) @@ -1217,12 +1234,19 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con #endif // Q_OS_WIN #if defined(QT_USE_SLOG2) - slog2_default_handler(type, logMessage.toLocal8Bit().constData()); + static const bool logToConsole = qEnvironmentVariableIsSet("QT_LOGGING_TO_CONSOLE"); + if (!logToConsole) { + slog2_default_handler(type, logMessage.toLocal8Bit().constData()); + } else { + fprintf(stderr, "%s", logMessage.toLocal8Bit().constData()); + fflush(stderr); + } #elif defined(QT_USE_JOURNALD) && !defined(QT_BOOTSTRAPPED) // We use isatty to catch the obvious case of someone running something interactively. - // We also support an environment variable for Qt Creator use, or more complicated cases like subprocesses. - static bool logToConsole = isatty(fileno(stdin)) || !qEnvironmentVariableIsEmpty("QT_NO_JOURNALD_LOG"); - if (Q_LIKELY(!logToConsole)) { + // We also support environment variables for Qt Creator use, or more complicated cases + // like subprocesses. + static const LogDestination logdest("QT_NO_JOURNALD_LOG", isatty(fileno(stdin))); + if (Q_LIKELY(!logdest.toConsole)) { // remove trailing \n, systemd appears to want them newline-less logMessage.chop(1); systemd_default_message_handler(type, context, logMessage); @@ -1231,8 +1255,8 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con fflush(stderr); } #elif defined(Q_OS_ANDROID) - static bool logToAndroid = qEnvironmentVariableIsEmpty("QT_ANDROID_PLAIN_LOG"); - if (logToAndroid) { + static const LogDestination logdest("QT_ANDROID_PLAIN_LOG", false); + if (!logdest.toConsole) { android_default_message_handler(type, context, logMessage); } else { fprintf(stderr, "%s", logMessage.toLocal8Bit().constData()); diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp index d2c8d37d4a..f7e58a7bed 100644 --- a/src/corelib/io/qfiledevice.cpp +++ b/src/corelib/io/qfiledevice.cpp @@ -139,10 +139,9 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum) are returned and on Windows the rights of the current user are returned. This behavior might change in a future Qt version. - Note that Qt does not by default check for permissions on NTFS - file systems, as this may decrease the performance of file - handling considerably. It is possible to force permission checking - on NTFS by including the following code in your source: + \note On NTFS file systems, ownership and permissions checking is + disabled by default for performance reasons. To enable it, + include the following line: \snippet ntfsp.cpp 0 diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 2cf97ef94e..60f7e47e62 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -271,6 +271,17 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) groupId(). You can examine a file's permissions and ownership in a single statement using the permission() function. + \note On NTFS file systems, ownership and permissions checking is + disabled by default for performance reasons. To enable it, + include the following line: + + \snippet ntfsp.cpp 0 + + Permission checking is then turned on and off by incrementing and + decrementing \c qt_ntfs_permission_lookup by 1. + + \snippet ntfsp.cpp 1 + \section1 Performance Issues Some of QFileInfo's functions query the file system, but for diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp index 53cf6158ad..8b6ceebc62 100644 --- a/src/corelib/io/qfilesystemengine.cpp +++ b/src/corelib/io/qfilesystemengine.cpp @@ -224,7 +224,7 @@ bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data) return false; } -#if defined(Q_OS_QNX) +#if defined(QT_EXT_QNX_READDIR_R) static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32) { statBuf64->st_mode = statBuf32.st_mode; @@ -289,7 +289,7 @@ void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer) void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry) { -#if defined(Q_OS_QNX) +#if defined(QT_EXT_QNX_READDIR_R) knownFlagsMask = 0; entryFlags = 0; for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry); diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h index 4164020359..18a9c2dbda 100644 --- a/src/corelib/io/qfilesystemiterator_p.h +++ b/src/corelib/io/qfilesystemiterator_p.h @@ -95,10 +95,10 @@ private: #else QT_DIR *dir; QT_DIRENT *dirEntry; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) || defined(QT_EXT_QNX_READDIR_R) // for readdir_r QScopedPointer mt_file; -#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) +#if defined(QT_EXT_QNX_READDIR_R) // for _readdir_r size_t direntSize; #endif diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp index 0b59aa169a..0f9bbd8a29 100644 --- a/src/corelib/io/qfilesystemiterator_unix.cpp +++ b/src/corelib/io/qfilesystemiterator_unix.cpp @@ -70,7 +70,7 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi if (!nativePath.endsWith('/')) nativePath.append('/'); -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) || defined(QT_EXT_QNX_READDIR_R) // ### Race condition; we should use fpathconf and dirfd(). size_t maxPathName = ::pathconf(nativePath.constData(), _PC_NAME_MAX); if (maxPathName == size_t(-1)) @@ -81,13 +81,14 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi Q_CHECK_PTR(p); mt_file.reset(p); -#if defined(Q_OS_QNX) && defined(__EXT_QNX__READDIR_R) +#if defined(QT_EXT_QNX_READDIR_R) direntSize = maxPathName; - // Include extra stat information in the readdir() call (d_stat member of dirent_extra_stat). - // This is used in QFileSystemMetaData::fillFromDirEnt() to avoid extra stat() calls when iterating - // over directories - if (dircntl(dir, D_SETFLAG, D_FLAG_STAT) == -1) + // Include extra stat information in the readdir() call (d_stat member of + // dirent_extra_stat). This is used in QFileSystemMetaData::fillFromDirEnt() to + // avoid extra stat() calls when iterating over directories + int flags = dircntl(dir, D_GETFLAG) | D_FLAG_STAT | D_FLAG_FILTER; + if (dircntl(dir, D_SETFLAG, flags) == -1) lastError = errno; #endif #endif @@ -105,7 +106,7 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa if (!dir) return false; -#if defined(Q_OS_QNX) && defined(QT_EXT_QNX_READDIR_R) +#if defined(QT_EXT_QNX_READDIR_R) lastError = QT_EXT_QNX_READDIR_R(dir, mt_file.data(), &dirEntry, direntSize); if (lastError) return false; diff --git a/src/corelib/io/qfilesystemwatcher_polling.cpp b/src/corelib/io/qfilesystemwatcher_polling.cpp index 689f05bb1b..401f95ae82 100644 --- a/src/corelib/io/qfilesystemwatcher_polling.cpp +++ b/src/corelib/io/qfilesystemwatcher_polling.cpp @@ -65,14 +65,16 @@ QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths, if (!fi.exists()) continue; if (fi.isDir()) { - if (!directories->contains(path)) - directories->append(path); + if (directories->contains(path)) + continue; + directories->append(path); if (!path.endsWith(QLatin1Char('/'))) fi = QFileInfo(path + QLatin1Char('/')); this->directories.insert(path, fi); } else { - if (!files->contains(path)) - files->append(path); + if (files->contains(path)) + continue; + files->append(path); this->files.insert(path, fi); } it.remove(); diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index df65aebcff..7dd2125e70 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -318,6 +318,7 @@ bool QWindowsPipeReader::waitForPipeClosed(int msecs) QElapsedTimer stopWatch; stopWatch.start(); forever { + waitForReadyRead(0); checkPipeState(); if (pipeBroken) return true; diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp index daa8068734..daad542705 100644 --- a/src/corelib/io/qwindowspipewriter.cpp +++ b/src/corelib/io/qwindowspipewriter.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ #include "qwindowspipewriter_p.h" -#include QT_BEGIN_NAMESPACE diff --git a/src/corelib/kernel/qmath.cpp b/src/corelib/kernel/qmath.cpp index b1860fa24a..9f276b4ca9 100644 --- a/src/corelib/kernel/qmath.cpp +++ b/src/corelib/kernel/qmath.cpp @@ -303,88 +303,4 @@ const qreal qt_sine_table[QT_SINE_TABLE_SIZE] = { qreal(-0.024541228522912448) }; -/*! - \headerfile - \title Generic Math Declarations - \ingroup funclists - - \brief The header file includes generic math declarations. - - These functions are partly convenience definitions for basic - operations, for instance not available in the Standard Template Library et - al. -*/ - -/*! - \fn float qDegreesToRadians(float degrees) - \relates - \since 5.1 - - \brief The function converts the \a degrees in float to radians. - - The purpose of the function is to aid the conversion as such a convenient - function is not part of the Standard Template Library, i.e. in or - elsewhere. - - Example: - - \snippet code/src_corelib_kernel_qmath.cpp 0 - - \sa qRadiansToDegrees() -*/ - -/*! - \fn double qDegreesToRadians(double degrees) - \relates - \since 5.1 - - \brief The function converts the \a degrees in double to radians. - - The purpose of the function is to aid the conversion as such a convenient - function is not part of the Standard Template Library, i.e. in or - elsewhere. - - Example: - - \snippet code/src_corelib_kernel_qmath.cpp 1 - - \sa qRadiansToDegrees() -*/ - -/*! - \fn float qRadiansToDegrees(float radians) - \relates - \since 5.1 - - \brief The function converts the \a radians in float to degrees. - - The purpose of the function is to aid the conversion as such a convenient - function is not part of the Standard Template Library, i.e. in or - elsewhere. - - Example: - - \snippet code/src_corelib_kernel_qmath.cpp 2 - - \sa qDegreesToRadians() -*/ - -/*! - \fn double qRadiansToDegrees(double radians) - \relates - \since 5.1 - - \brief The function converts the \a radians in double to degrees. - - The purpose of the function is to aid the conversion as such a convenient - function is not part of the Standard Template Library, i.e. in or - elsewhere. - - Example: - - \snippet code/src_corelib_kernel_qmath.cpp 3 - - \sa qDegreesToRadians() -*/ - QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmath.qdoc b/src/corelib/kernel/qmath.qdoc index 06d8db9277..04dbbb0a3b 100644 --- a/src/corelib/kernel/qmath.qdoc +++ b/src/corelib/kernel/qmath.qdoc @@ -26,10 +26,15 @@ ****************************************************************************/ /*! - \headerfile - \title Math Functions + \headerfile + \title Generic Math Functions \ingroup funclists - \brief The header provides various math functions. + + \brief The header file provides various math functions. + + These functions are partly convenience definitions for basic math operations + not available in the C or Standard Template Libraries. + \pagekeywords math trigonometry qmath floor ceiling absolute sine cosine tangent inverse tan exponent power natural logarithm */ @@ -40,7 +45,7 @@ The ceiling is the smallest integer that is not less than \a v. For example, if \a v is 41.2, then the ceiling is 42. - \relates + \relates \sa qFloor() */ @@ -51,7 +56,7 @@ The floor is the largest integer that is not greater than \a v. For example, if \a v is 41.2, then the floor is 41. - \relates + \relates \sa qCeil() */ @@ -59,14 +64,14 @@ \fn qreal qFabs(qreal v) Returns the absolute value of \a v as a qreal. - \relates + \relates */ /*! \fn qreal qSin(qreal v) Returns the sine of the angle \a v in radians. - \relates + \relates \sa qCos(), qTan() */ @@ -74,7 +79,7 @@ \fn qreal qCos(qreal v) Returns the cosine of an angle \a v in radians. - \relates + \relates \sa qSin(), qTan() */ @@ -82,7 +87,7 @@ \fn qreal qTan(qreal v) Returns the tangent of an angle \a v in radians. - \relates + \relates \sa qSin(), qCos() */ @@ -91,7 +96,7 @@ Returns the arccosine of \a v as an angle in radians. Arccosine is the inverse operation of cosine. - \relates + \relates \sa qAtan(), qAsin(), qCos() */ @@ -100,7 +105,7 @@ Returns the arcsine of \a v as an angle in radians. Arcsine is the inverse operation of sine. - \relates + \relates \sa qSin(), qAtan(), qAcos() */ @@ -109,7 +114,7 @@ Returns the arctangent of \a v as an angle in radians. Arctangent is the inverse operation of tangent. - \relates + \relates \sa qTan(), qAcos(), qAsin() */ @@ -118,7 +123,7 @@ Returns the arctangent of a point specified by the coordinates \a y and \a x. This function will return the angle (argument) of that point. - \relates + \relates \sa qAtan() */ @@ -127,7 +132,7 @@ Returns the square root of \a v. This function returns a NaN if \a v is a negative number. - \relates + \relates \sa qPow() */ @@ -135,7 +140,7 @@ \fn qreal qLn(qreal v) Returns the natural logarithm of \a v. Natural logarithm uses base e. - \relates + \relates \sa qExp() */ @@ -143,7 +148,7 @@ \fn qreal qExp(qreal v) Returns the exponential function of \c e to the power of \a v. - \relates + \relates \sa qLn() */ @@ -152,6 +157,62 @@ Returns the value of \a x raised to the power of \a y. That is, \a x is the base and \a y is the exponent. - \relates + \relates \sa qSqrt() */ + +/*! + \fn float qDegreesToRadians(float degrees) + \relates + \since 5.1 + + This function converts the \a degrees in float to radians. + + Example: + + \snippet code/src_corelib_kernel_qmath.cpp 0 + + \sa qRadiansToDegrees() +*/ + +/*! + \fn double qDegreesToRadians(double degrees) + \relates + \since 5.1 + + This function converts the \a degrees in double to radians. + + Example: + + \snippet code/src_corelib_kernel_qmath.cpp 1 + + \sa qRadiansToDegrees() +*/ + +/*! + \fn float qRadiansToDegrees(float radians) + \relates + \since 5.1 + + This function converts the \a radians in float to degrees. + + Example: + + \snippet code/src_corelib_kernel_qmath.cpp 2 + + \sa qDegreesToRadians() +*/ + +/*! + \fn double qRadiansToDegrees(double radians) + \relates + \since 5.1 + + This function converts the \a radians in double to degrees. + + Example: + + \snippet code/src_corelib_kernel_qmath.cpp 3 + + \sa qDegreesToRadians() +*/ diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 0184e9a9e7..c0773882f3 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4071,18 +4071,21 @@ QDebug operator<<(QDebug dbg, const QObject *o) { \macro Q_CLASSINFO(Name, Value) \relates QObject - This macro associates extra information to the class, which is - available using QObject::metaObject(). Except for the ActiveQt - extension, Qt doesn't use this information. + This macro associates extra information to the class, which is available + using QObject::metaObject(). Qt makes only limited use of this feature, in + the \l{Active Qt}, \l{Qt D-Bus} and \l{Qt QML} modules. - The extra information takes the form of a \a Name string and a \a - Value literal string. + The extra information takes the form of a \a Name string and a \a Value + literal string. Example: \snippet code/src_corelib_kernel_qobject.cpp 35 \sa QMetaObject::classInfo() + \sa QAxFactory + \sa {Using Qt D-Bus Adaptors} + \sa {Extending QML - Default Property Example} */ /*! @@ -4441,6 +4444,8 @@ void qDeleteInEventHandler(QObject *o) \snippet code/src_corelib_kernel_qobject.cpp 46 The connection will automatically disconnect if the sender is destroyed. + However, you should take care that any objects used within the functor + are still alive when the signal is emitted. \note If the compiler does not support C++11 variadic templates, the number of arguments in the signal or slot are limited to 6, and the functor object @@ -4478,6 +4483,8 @@ void qDeleteInEventHandler(QObject *o) The connection will automatically disconnect if the sender or the context is destroyed. + However, you should take care that any objects used within the functor + are still alive when the signal is emitted. \note If the compiler does not support C++11 variadic templates, the number of arguments in the signal or slot are limited to 6, and the functor object diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index ee6ef23139..a54690606a 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -549,7 +549,7 @@ template inline const char * qobject_interface_iid() Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *); #endif -class Q_CORE_EXPORT QSignalBlocker +class QSignalBlocker { public: inline explicit QSignalBlocker(QObject *o); diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 843a6edce1..94c77302dd 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -465,6 +465,12 @@ QTranslator::~QTranslator() \li \c /opt/foolib/foo.qm \li \c /opt/foolib/foo \endlist + + Usually, it is better to use the QTranslator::load(const QLocale &, + const QString &, const QString &, const QString &, const QString &) + function instead, because it uses \l{QLocale::uiLanguages()} and not simply + the locale name, which refers to the formatting of dates and numbers and not + necessarily the UI language. */ bool QTranslator::load(const QString & filename, const QString & directory, diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index a12636778e..bdc3463b9f 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -63,6 +63,7 @@ #include #ifdef Q_OS_WINRT +#include #include #endif @@ -680,21 +681,11 @@ bool QThread::wait(unsigned long time) break; } #else // !Q_OS_WINRT - if (d->handle->joinable()) { - HANDLE handle = d->handle->native_handle(); - switch (WaitForSingleObjectEx(handle, time, FALSE)) { - case WAIT_OBJECT_0: - ret = true; - d->handle->join(); - break; - case WAIT_FAILED: - qErrnoWarning("QThread::wait: WaitForSingleObjectEx() failed"); - break; - case WAIT_ABANDONED: - case WAIT_TIMEOUT: - default: - break; - } + if (!d->finished) { + QElapsedTimer timer; + timer.start(); + while (timer.elapsed() < time && !d->finished) + yieldCurrentThread(); } #endif // Q_OS_WINRT diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index 45587b1214..2d744f97c0 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -75,10 +75,13 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, && !(alignment & (alignment - 1))); // Don't allocate empty headers - if (!(options & RawData) && !capacity) - return !(options & Unsharable) - ? const_cast(&qt_array_empty) - : const_cast(&qt_array_unsharable_empty); + if (!(options & RawData) && !capacity) { +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + if (options & Unsharable) + return const_cast(&qt_array_unsharable_empty); +#endif + return const_cast(&qt_array_empty); + } size_t headerSize = sizeof(QArrayData); @@ -118,8 +121,10 @@ void QArrayData::deallocate(QArrayData *data, size_t objectSize, && !(alignment & (alignment - 1))); Q_UNUSED(objectSize) Q_UNUSED(alignment) +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) if (data == &qt_array_unsharable_empty) return; +#endif Q_ASSERT_X(!data->ref.isStatic(), "QArrayData::deallocate", "Static data can not be deleted"); ::free(data); diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h index 534f310d36..5a8c46b582 100644 --- a/src/corelib/tools/qarraydata.h +++ b/src/corelib/tools/qarraydata.h @@ -80,7 +80,9 @@ struct Q_CORE_EXPORT QArrayData enum AllocationOption { CapacityReserved = 0x1, +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) Unsharable = 0x2, +#endif RawData = 0x4, Grow = 0x8, @@ -99,8 +101,10 @@ struct Q_CORE_EXPORT QArrayData AllocationOptions detachFlags() const { AllocationOptions result; +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) if (!ref.isSharable()) result |= Unsharable; +#endif if (capacityReserved) result |= CapacityReserved; return result; diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h index 533f7a306f..2245106ec0 100644 --- a/src/corelib/tools/qarraydatapointer.h +++ b/src/corelib/tools/qarraydatapointer.h @@ -134,6 +134,7 @@ public: return (!d->isMutable() || d->ref.isShared()); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) void setSharable(bool sharable) { if (needsDetach()) { @@ -147,6 +148,9 @@ public: } } + bool isSharable() const { return d->isSharable(); } +#endif + void swap(QArrayDataPointer &other) { qSwap(d, other.d); diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h index 88758bdd6d..9ef4ee91c6 100644 --- a/src/corelib/tools/qchar.h +++ b/src/corelib/tools/qchar.h @@ -358,6 +358,9 @@ public: case QChar::Joining_Causing: return QChar::Center; case QChar::Joining_Dual: return QChar::Dual; case QChar::Joining_Right: return QChar::Right; + case QChar::Joining_None: + case QChar::Joining_Left: + case QChar::Joining_Transparent: default: return QChar::OtherJoining; } } diff --git a/src/corelib/tools/qcollator.cpp b/src/corelib/tools/qcollator.cpp index 9c97d6b158..f7dfaa7d33 100644 --- a/src/corelib/tools/qcollator.cpp +++ b/src/corelib/tools/qcollator.cpp @@ -205,6 +205,11 @@ QLocale QCollator::locale() const By default this mode is off. + \note On Windows, this functionality makes use of the \l{ICU} library. If Qt was + compiled without ICU support, it falls back to code using native Windows API, + which only works from Windows 7 onwards. On older versions of Windows, it will not work + and a warning will be emitted at runtime. + \sa numericMode() */ diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index d601ddb819..e05ef33aa2 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -104,7 +104,9 @@ public: inline void detach() { if (d->ref.load() != 1) detach_helper(); } inline bool isDetached() const { return d->ref.load() == 1; } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } +#endif QContiguousCache &operator=(const QContiguousCache &other); #ifdef Q_COMPILER_RVALUE_REFS diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 67924c0888..1d76a2b3d1 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -326,7 +326,9 @@ public: inline void detach() { if (d->ref.isShared()) detach_helper(); } inline bool isDetached() const { return !d->ref.isShared(); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QHashData::shared_null) d->sharable = sharable; } +#endif inline bool isSharedWith(const QHash &other) const { return d == other.d; } void clear(); diff --git a/src/corelib/tools/qlinkedlist.h b/src/corelib/tools/qlinkedlist.h index bdacdbcd26..3377d1bbc3 100644 --- a/src/corelib/tools/qlinkedlist.h +++ b/src/corelib/tools/qlinkedlist.h @@ -106,7 +106,9 @@ public: inline void detach() { if (d->ref.isShared()) detach_helper2(this->e); } inline bool isDetached() const { return !d->ref.isShared(); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QLinkedListData::shared_null) d->sharable = sharable; } +#endif inline bool isSharedWith(const QLinkedList &other) const { return d == other.d; } inline bool isEmpty() const { return d->size == 0; } diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 3a0d01aa8d..9e4ba70908 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -146,6 +146,7 @@ public: } inline bool isDetached() const { return !d->ref.isShared(); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { if (sharable == d->ref.isSharable()) @@ -155,6 +156,7 @@ public: if (d != &QListData::shared_null) d->ref.setSharable(sharable); } +#endif inline bool isSharedWith(const QList &other) const { return d == other.d; } inline bool isEmpty() const { return p.isEmpty(); } diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 487039ccfb..76f8bd6f17 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -377,6 +377,7 @@ public: inline void detach() { if (d->ref.isShared()) detach_helper(); } inline bool isDetached() const { return !d->ref.isShared(); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { if (sharable == d->ref.isSharable()) @@ -386,6 +387,7 @@ public: // Don't call on shared_null d->ref.setSharable(sharable); } +#endif inline bool isSharedWith(const QMap &other) const { return d == other.d; } void clear(); diff --git a/src/corelib/tools/qrefcount.h b/src/corelib/tools/qrefcount.h index 84314b1fcc..3a8f0f3982 100644 --- a/src/corelib/tools/qrefcount.h +++ b/src/corelib/tools/qrefcount.h @@ -55,8 +55,10 @@ class RefCount public: inline bool ref() Q_DECL_NOTHROW { int count = atomic.load(); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) if (count == 0) // !isSharable return false; +#endif if (count != -1) // !isStatic atomic.ref(); return true; @@ -64,13 +66,16 @@ public: inline bool deref() Q_DECL_NOTHROW { int count = atomic.load(); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) if (count == 0) // !isSharable return false; +#endif if (count == -1) // isStatic return true; return atomic.deref(); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) bool setSharable(bool sharable) Q_DECL_NOTHROW { Q_ASSERT(!isShared()); @@ -80,17 +85,18 @@ public: return atomic.testAndSetRelaxed(1, 0); } - bool isStatic() const Q_DECL_NOTHROW - { - // Persistent object, never deleted - return atomic.load() == -1; - } - bool isSharable() const Q_DECL_NOTHROW { // Sharable === Shared ownership. return atomic.load() != 0; } +#endif + + bool isStatic() const Q_DECL_NOTHROW + { + // Persistent object, never deleted + return atomic.load() == -1; + } bool isShared() const Q_DECL_NOTHROW { diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp index cadf2da019..fbcd271f1d 100644 --- a/src/corelib/tools/qregexp.cpp +++ b/src/corelib/tools/qregexp.cpp @@ -388,7 +388,7 @@ int qFindString(const QChar *haystack, int haystackLen, int from, Note: Quantifiers are normally "greedy". They always match as much text as they can. For example, \b{0+} matches the first zero it finds and all the consecutive zeros after the first zero. Applied - to '20005', it matches'2\underline{000}5'. Quantifiers can be made + to '20005', it matches '2\underline{000}5'. Quantifiers can be made non-greedy, see setMinimal(). \target capturing parentheses @@ -678,7 +678,7 @@ int qFindString(const QChar *haystack, int haystackLen, int from, QRegExp can match case insensitively using setCaseSensitivity(), and can use non-greedy matching, see setMinimal(). By default QRegExp uses full regexps but this can be changed with - setWildcard(). Searching can be forward with indexIn() or backward + setPatternSyntax(). Searching can be done forward with indexIn() or backward with lastIndexIn(). Captured text can be accessed using capturedTexts() which returns a string list of all captured strings, or using cap() which returns the captured string for the diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index 291c8fe4f9..992243def6 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -91,7 +91,9 @@ public: inline void detach() { q_hash.detach(); } inline bool isDetached() const { return q_hash.isDetached(); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { q_hash.setSharable(sharable); } +#endif inline void clear() { q_hash.clear(); } diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp index da447157ff..03966ab1d6 100644 --- a/src/corelib/tools/qsize.cpp +++ b/src/corelib/tools/qsize.cpp @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE width and height can be swapped using the transpose() function. The isValid() function determines if a size is valid (a valid size - has both width and height greater than zero). The isEmpty() + has both width and height greater than or equal to zero). The isEmpty() function returns \c true if either of the width and height is less than, or equal to, zero, while the isNull() function returns \c true only if both the width and the height is zero. diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 79365b11b1..aac9c493c3 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -4331,14 +4331,6 @@ QByteArray QString::toLocal8Bit_helper(const QChar *data, int size) UTF-8 is a Unicode codec and can represent all characters in a Unicode string like QString. - However, in the Unicode range, there are certain codepoints that are not - considered characters. The Unicode standard reserves the last two - codepoints in each Unicode Plane (U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, - U+2FFFE, etc.), as well as 32 codepoints in the range U+FDD0..U+FDEF, - inclusive, as non-characters. If any of those appear in the string, they - may be discarded and will not appear in the UTF-8 representation, or they - may be replaced by one or more replacement characters. - \sa fromUtf8(), toLatin1(), toLocal8Bit(), QTextCodec */ @@ -4493,10 +4485,10 @@ QString QString::fromLocal8Bit_helper(const char *str, int size) sequences, non-characters, overlong sequences or surrogate codepoints encoded into UTF-8. - Non-characters are codepoints that the Unicode standard reserves and must - not be used in text interchange. They are the last two codepoints in each - Unicode Plane (U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, etc.), as well - as 32 codepoints in the range U+FDD0..U+FDEF, inclusive. + This function can be used to process incoming data incrementally as long as + all UTF-8 characters are terminated within the incoming data. Any + unterminated characters at the end of the string will be replaced or + suppressed. In order to do stateful decoding, please use \l QTextDecoder. \sa toUtf8(), fromLatin1(), fromLocal8Bit() */ @@ -9517,14 +9509,6 @@ QByteArray QStringRef::toLocal8Bit() const UTF-8 is a Unicode codec and can represent all characters in a Unicode string like QString. - However, in the Unicode range, there are certain codepoints that are not - considered characters. The Unicode standard reserves the last two - codepoints in each Unicode Plane (U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, - U+2FFFE, etc.), as well as 16 codepoints in the range U+FDD0..U+FDDF, - inclusive, as non-characters. If any of those appear in the string, they - may be discarded and will not appear in the UTF-8 representation, or they - may be replaced by one or more replacement characters. - \sa toLatin1(), toLocal8Bit(), QTextCodec */ QByteArray QStringRef::toUtf8() const diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 2d9a42957e..359d0c49e5 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -954,6 +954,9 @@ public: case QChar::Joining_Causing: return QChar::Center; case QChar::Joining_Dual: return QChar::Dual; case QChar::Joining_Right: return QChar::Right; + case QChar::Joining_None: + case QChar::Joining_Left: + case QChar::Joining_Transparent: default: return QChar::OtherJoining; } } diff --git a/src/corelib/tools/qtimezone.cpp b/src/corelib/tools/qtimezone.cpp index b30caf4289..e17ff2b249 100644 --- a/src/corelib/tools/qtimezone.cpp +++ b/src/corelib/tools/qtimezone.cpp @@ -417,6 +417,13 @@ QTimeZone::~QTimeZone() { } +/*! + \fn QTimeZone::swap(QTimeZone &other) + + Swaps this time zone instance with \a other. This function is very + fast and never fails. +*/ + /*! Assignment operator, assign \a other to this. */ diff --git a/src/corelib/tools/qunicodetools.cpp b/src/corelib/tools/qunicodetools.cpp index fac795051a..fc36d07a4a 100644 --- a/src/corelib/tools/qunicodetools.cpp +++ b/src/corelib/tools/qunicodetools.cpp @@ -667,7 +667,7 @@ Q_CORE_EXPORT void initCharAttributes(const ushort *string, int length, // ---------------------------------------------------------------------------- // -// The Unicode script property. See http://www.unicode.org/reports/tr24/ (some very old version) +// The Unicode script property. See http://www.unicode.org/reports/tr24/tr24-21.html // // ---------------------------------------------------------------------------- @@ -689,15 +689,36 @@ Q_CORE_EXPORT void initScripts(const ushort *string, int length, uchar *scripts) const QUnicodeTables::Properties *prop = QUnicodeTables::properties(ucs4); - if (Q_LIKELY(prop->script == script || prop->script == QChar::Script_Inherited)) + if (Q_LIKELY(prop->script == script || prop->script <= QChar::Script_Inherited)) continue; // Never break between a combining mark (gc= Mc, Mn or Me) and its base character. // Thus, a combining mark — whatever its script property value is — should inherit // the script property value of its base character. static const int test = (FLAG(QChar::Mark_NonSpacing) | FLAG(QChar::Mark_SpacingCombining) | FLAG(QChar::Mark_Enclosing)); - if (Q_UNLIKELY(FLAG(prop->category) & test)) - continue; + if (Q_UNLIKELY(FLAG(prop->category) & test)) { + // In cases where the base character itself has the Common script property value, + // and it is followed by one or more combining marks with a specific script property value, + // it may be even better for processing to let the base acquire the script property value + // from the first mark. This approach can be generalized by treating all the characters + // of a combining character sequence as having the script property value + // of the first non-Inherited, non-Common character in the sequence if there is one, + // and otherwise treating all the characters as having the Common script property value. + if (Q_LIKELY(script > QChar::Script_Common || prop->script <= QChar::Script_Common)) + continue; + + script = QChar::Script(prop->script); + } + + if (Q_LIKELY(script != QChar::Script_Common)) { + // override preceding Common-s + while (sor > 0 && scripts[sor - 1] == QChar::Script_Common) + --sor; + } else { + // see if we are inheriting preceding run + if (sor > 0) + script = scripts[sor - 1]; + } while (sor < eor) scripts[sor++] = script; @@ -705,6 +726,15 @@ Q_CORE_EXPORT void initScripts(const ushort *string, int length, uchar *scripts) script = prop->script; } eor = length; + if (Q_LIKELY(script != QChar::Script_Common)) { + // override preceding Common-s + while (sor > 0 && scripts[sor - 1] == QChar::Script_Common) + --sor; + } else { + // see if we are inheriting preceding run + if (sor > 0) + script = scripts[sor - 1]; + } while (sor < eor) scripts[sor++] = script; } diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 22031645dc..0a32c96958 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -107,6 +107,7 @@ public: inline void detach(); inline bool isDetached() const { return !d->ref.isShared(); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) inline void setSharable(bool sharable) { if (sharable == d->ref.isSharable()) @@ -122,6 +123,7 @@ public: } Q_ASSERT(d->ref.isSharable() == sharable); } +#endif inline bool isSharedWith(const QVector &other) const { return d == other.d; } @@ -348,10 +350,12 @@ template void QVector::detach() { if (!isDetached()) { - if (d->alloc) - reallocData(d->size, int(d->alloc)); - else +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + if (!d->alloc) d = Data::unsharableEmpty(); + else +#endif + reallocData(d->size, int(d->alloc)); } Q_ASSERT(isDetached()); } @@ -503,7 +507,9 @@ void QVector::reallocData(const int asize, const int aalloc, QArrayData::Allo x = Data::allocate(aalloc, options); Q_CHECK_PTR(x); // aalloc is bigger then 0 so it is not [un]sharedEmpty +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) Q_ASSERT(x->ref.isSharable() || options.testFlag(QArrayData::Unsharable)); +#endif Q_ASSERT(!x->ref.isStatic()); x->size = asize; @@ -569,7 +575,9 @@ void QVector::reallocData(const int asize, const int aalloc, QArrayData::Allo Q_ASSERT(d->data()); Q_ASSERT(uint(d->size) <= d->alloc); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) Q_ASSERT(d != Data::unsharableEmpty()); +#endif Q_ASSERT(aalloc ? d != Data::sharedNull() : d == Data::sharedNull()); Q_ASSERT(d->alloc >= uint(aalloc)); Q_ASSERT(d->size == asize); diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 863cf03439..57a9591060 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -163,10 +163,10 @@ contains(QT_CONFIG,icu) { LIBS_PRIVATE += -lsicuin -lsicuuc -lsicudt } } else { - LIBS_PRIVATE += -licuin -licuuc + LIBS_PRIVATE += -licuin -licuuc -licudt } } else { - LIBS_PRIVATE += -licui18n -licuuc + LIBS_PRIVATE += -licui18n -licuuc -licudata } } else: win32 { SOURCES += tools/qcollator_win.cpp diff --git a/src/dbus/Qt5DBusMacros.cmake b/src/dbus/Qt5DBusMacros.cmake index ff497e8ebc..2364c6710c 100644 --- a/src/dbus/Qt5DBusMacros.cmake +++ b/src/dbus/Qt5DBusMacros.cmake @@ -32,6 +32,7 @@ include(MacroAddFileDependencies) +include(CMakeParseArguments) function(QT5_ADD_DBUS_INTERFACE _sources _interface _basename) get_filename_component(_infile ${_interface} ABSOLUTE) diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 6af692984a..af84eb7342 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -1,8 +1,7 @@ TARGET = QtGui QT = core-private -MODULE_CONFIG = needs_qpa_plugin -contains(QT_CONFIG, opengl.*):MODULE_CONFIG += opengl +contains(QT_CONFIG, opengl.*): MODULE_CONFIG = opengl DEFINES += QT_NO_USING_NAMESPACE diff --git a/src/gui/image/qgifhandler.cpp b/src/gui/image/qgifhandler.cpp index eeb62af4e5..19b838240f 100644 --- a/src/gui/image/qgifhandler.cpp +++ b/src/gui/image/qgifhandler.cpp @@ -359,6 +359,13 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, memset(bits, 0, image->byteCount()); } + // Check if the previous attempt to create the image failed. If it + // did then the image is broken and we should give up. + if (image->isNull()) { + state = Error; + return -1; + } + disposePrevious(image); disposed = false; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index a49f0ce496..827bf0164b 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1880,7 +1880,11 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate return; if (previous) { - QFocusEvent focusOut(QEvent::FocusOut, e->reason); + Qt::FocusReason r = e->reason; + if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) && + newFocus && (newFocus->flags() & Qt::Popup) == Qt::Popup) + r = Qt::PopupFocusReason; + QFocusEvent focusOut(QEvent::FocusOut, r); QCoreApplication::sendSpontaneousEvent(previous, &focusOut); QObject::disconnect(previous, SIGNAL(focusObjectChanged(QObject*)), qApp, SLOT(_q_updateFocusObject(QObject*))); @@ -1889,7 +1893,11 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate } if (QGuiApplicationPrivate::focus_window) { - QFocusEvent focusIn(QEvent::FocusIn, e->reason); + Qt::FocusReason r = e->reason; + if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) && + previous && (previous->flags() & Qt::Popup) == Qt::Popup) + r = Qt::PopupFocusReason; + QFocusEvent focusIn(QEvent::FocusIn, r); QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn); QObject::connect(QGuiApplicationPrivate::focus_window, SIGNAL(focusObjectChanged(QObject*)), qApp, SLOT(_q_updateFocusObject(QObject*))); diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 7fa0452fe5..9bc4373860 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -61,6 +61,10 @@ #include +#ifndef QT_OPENGL_ES_2 +#include +#endif + QT_BEGIN_NAMESPACE class QOpenGLVersionProfilePrivate @@ -360,13 +364,15 @@ int QOpenGLContextPrivate::maxTextureSize() funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); #ifndef QT_OPENGL_ES - if (!q->isES()) { + if (!q->isOpenGLES()) { GLenum proxy = GL_PROXY_TEXTURE_2D; GLint size; GLint next = 64; funcs->glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - funcs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size); + QOpenGLFunctions_1_0 *gl1funcs = q->versionFunctions(); + gl1funcs->initializeOpenGLFunctions(); + gl1funcs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size); if (size == 0) { return max_texture_size; } @@ -377,7 +383,7 @@ int QOpenGLContextPrivate::maxTextureSize() if (next > max_texture_size) break; funcs->glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - funcs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next); + gl1funcs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next); } while (next > size); max_texture_size = size; @@ -730,7 +736,7 @@ QOpenGLFunctions *QOpenGLContext::functions() const QAbstractOpenGLFunctions *QOpenGLContext::versionFunctions(const QOpenGLVersionProfile &versionProfile) const { #ifndef QT_OPENGL_ES_2 - if (isES()) { + if (isOpenGLES()) { qWarning("versionFunctions: Not supported on OpenGL ES"); return 0; } @@ -1090,8 +1096,8 @@ void *QOpenGLContext::openGLModuleHandle() \enum QOpenGLContext::OpenGLModuleType This enum defines the type of the underlying OpenGL implementation. - \value DesktopGL Desktop OpenGL - \value GLES2 OpenGL ES 2.0 or higher + \value LibGL OpenGL + \value LibGLES OpenGL ES 2.0 or higher \since 5.3 */ @@ -1106,7 +1112,7 @@ void *QOpenGLContext::openGLModuleHandle() \note A desktop OpenGL implementation may be capable of creating ES-compatible contexts too. Therefore in most cases it is more appropriate to check QSurfaceFormat::renderableType() or using the - the convenience function isES(). + the convenience function isOpenGLES(). \note This function requires that the QGuiApplication instance is already created. @@ -1118,9 +1124,9 @@ QOpenGLContext::OpenGLModuleType QOpenGLContext::openGLModuleType() Q_ASSERT(qGuiApp); return QGuiApplicationPrivate::instance()->platformIntegration()->openGLModuleType(); #elif defined(QT_OPENGL_ES_2) - return GLES2; + return LibGLES; #else - return DesktopGL; + return LibGL; #endif } @@ -1134,7 +1140,7 @@ QOpenGLContext::OpenGLModuleType QOpenGLContext::openGLModuleType() \since 5.3 */ -bool QOpenGLContext::isES() const +bool QOpenGLContext::isOpenGLES() const { return format().renderableType() == QSurfaceFormat::OpenGLES; } diff --git a/src/gui/kernel/qopenglcontext.h b/src/gui/kernel/qopenglcontext.h index 736ae0c0b4..402989b4d0 100644 --- a/src/gui/kernel/qopenglcontext.h +++ b/src/gui/kernel/qopenglcontext.h @@ -198,13 +198,19 @@ public: static void *openGLModuleHandle(); enum OpenGLModuleType { - DesktopGL, - GLES2 + LibGL, + LibGLES, + + // ### + DesktopGL = LibGL, + GLES2 = LibGLES }; static OpenGLModuleType openGLModuleType(); - bool isES() const; + bool isOpenGLES() const; + + bool isES() const { return isOpenGLES(); } // ### Q_SIGNALS: void aboutToBeDestroyed(); diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h index 660fdd1298..8c6a0a04ca 100644 --- a/src/gui/kernel/qopenglcontext_p.h +++ b/src/gui/kernel/qopenglcontext_p.h @@ -127,7 +127,7 @@ private: class Q_GUI_EXPORT QOpenGLContextGroupPrivate : public QObjectPrivate { - Q_DECLARE_PUBLIC(QOpenGLContextGroup); + Q_DECLARE_PUBLIC(QOpenGLContextGroup) public: QOpenGLContextGroupPrivate() : m_context(0) diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 432199f142..f20482a859 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -510,14 +510,14 @@ void QPlatformIntegration::sync() a desktop OpenGL implementation may be capable of creating OpenGL ES-compatible contexts too. - \sa QOpenGLContext::openGLModuleType(), QOpenGLContext::isES() + \sa QOpenGLContext::openGLModuleType(), QOpenGLContext::isOpenGLES() \since 5.3 */ QOpenGLContext::OpenGLModuleType QPlatformIntegration::openGLModuleType() { qWarning("This plugin does not support dynamic OpenGL loading!"); - return QOpenGLContext::DesktopGL; + return QOpenGLContext::LibGL; } #endif diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h index 19e2d9bccf..b88f2a7e84 100644 --- a/src/gui/kernel/qplatformmenu.h +++ b/src/gui/kernel/qplatformmenu.h @@ -86,6 +86,9 @@ public: virtual void setChecked(bool isChecked) = 0; virtual void setShortcut(const QKeySequence& shortcut) = 0; virtual void setEnabled(bool enabled) = 0; + + virtual void setNativeContents(WId item) { Q_UNUSED(item); } + Q_SIGNALS: void activated(); void hovered(); @@ -118,6 +121,8 @@ public: setVisible(true); } + virtual void dismiss() { } // Closes this and all its related menu popups + virtual QPlatformMenuItem *menuItemAt(int position) const = 0; virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const = 0; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 2b0c95b2b6..4b36e5ca41 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -458,7 +458,7 @@ void QWindow::setVisible(bool visible) } #ifndef QT_NO_CURSOR - if (visible && d->hasCursor) + if (visible && (d->hasCursor || QGuiApplication::overrideCursor())) d->applyCursor(); #endif d->platformWindow->setVisible(visible); @@ -746,7 +746,7 @@ void QWindow::setTitle(const QString &title) d->windowTitle = title; changed = true; } - if (d->platformWindow) + if (d->platformWindow && type() != Qt::Desktop) d->platformWindow->setWindowTitle(title); if (changed) emit windowTitleChanged(title); diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp index a1215acb7e..1c4231b79f 100644 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -164,7 +164,7 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader; code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader; - if (context->isES()) + if (context->isOpenGLES()) code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_ES; else code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop; diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index 92a7330d6c..cc829df950 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -590,7 +590,7 @@ void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpen funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { - if (ctx->isES()) { + if (ctx->isOpenGLES()) { if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT24, size.width(), size.height()); @@ -602,7 +602,7 @@ void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpen GL_DEPTH_COMPONENT, size.width(), size.height()); } } else { - if (ctx->isES()) { + if (ctx->isOpenGLES()) { if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size.width(), size.height()); @@ -631,7 +631,7 @@ void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpen #ifdef QT_OPENGL_ES GLenum storage = GL_STENCIL_INDEX8; #else - GLenum storage = ctx->isES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; + GLenum storage = ctx->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; #endif if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) @@ -773,7 +773,7 @@ QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum tar Q_D(QOpenGLFramebufferObject); d->init(this, size, NoAttachment, target, #ifndef QT_OPENGL_ES_2 - QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8 + QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8 #else GL_RGBA #endif @@ -793,7 +793,7 @@ QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, GLenum Q_D(QOpenGLFramebufferObject); d->init(this, QSize(width, height), NoAttachment, target, #ifndef QT_OPENGL_ES_2 - QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8 + QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8 #else GL_RGBA #endif @@ -850,7 +850,7 @@ QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, Attach #ifdef QT_OPENGL_ES_2 internal_format = GL_RGBA; #else - internal_format = QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8; + internal_format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; #endif d->init(this, QSize(width, height), attachment, target, internal_format); } @@ -877,7 +877,7 @@ QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, Attachment #ifdef QT_OPENGL_ES_2 internal_format = GL_RGBA; #else - internal_format = QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8; + internal_format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; #endif d->init(this, size, attachment, target, internal_format); } diff --git a/src/gui/opengl/qopenglframebufferobject_p.h b/src/gui/opengl/qopenglframebufferobject_p.h index bd830b38e9..7a653bc16d 100644 --- a/src/gui/opengl/qopenglframebufferobject_p.h +++ b/src/gui/opengl/qopenglframebufferobject_p.h @@ -74,7 +74,7 @@ public: // context, so we need a fallback just to be safe, even though in pratice there // will usually be a context current. QOpenGLContext *ctx = QOpenGLContext::currentContext(); - const bool isES = ctx ? ctx->isES() : QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL; + const bool isES = ctx ? ctx->isOpenGLES() : QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL; internal_format = isES ? GL_RGBA : GL_RGBA8; #else internal_format = GL_RGBA; diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index eb2c98e1f5..bcb38ce7f1 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -256,7 +256,7 @@ QOpenGLExtensions::QOpenGLExtensions(QOpenGLContext *context) static int qt_gl_resolve_features() { QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (ctx->isES()) { + if (ctx->isOpenGLES()) { // OpenGL ES 2 int features = QOpenGLFunctions::Multitexture | QOpenGLFunctions::Shaders | @@ -367,7 +367,7 @@ static int qt_gl_resolve_extensions() if (extensionMatcher.match("GL_ARB_pixel_buffer_object")) extensions |= QOpenGLExtensions::PixelBufferObject; - if (ctx->isES()) { + if (ctx->isOpenGLES()) { if (format.majorVersion() >= 2) extensions |= QOpenGLExtensions::GenerateMipmap; if (extensionMatcher.match("GL_OES_mapbuffer")) @@ -2011,12 +2011,6 @@ void QOpenGLFunctions::initializeOpenGLFunctions() This convenience function will do nothing on OpenGL ES 1.x systems. */ -/*! - \fn void QOpenGLFunctions::glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) - - \internal -*/ - /*! \fn bool QOpenGLFunctions::isInitialized(const QOpenGLFunctionsPrivate *d) \internal @@ -2421,7 +2415,7 @@ static void QOPENGLF_APIENTRY qopenglfResolveClearColor(GLclampf red, GLclampf g static void QOPENGLF_APIENTRY qopenglfResolveClearDepthf(GLclampf depth) { - if (QOpenGLContext::currentContext()->isES()) { + if (QOpenGLContext::currentContext()->isOpenGLES()) { RESOLVE_FUNC_VOID(0, ClearDepthf)(depth); } else { RESOLVE_FUNC_VOID(0, ClearDepth)((GLdouble) depth); @@ -2470,7 +2464,7 @@ static void QOPENGLF_APIENTRY qopenglfResolveDepthMask(GLboolean flag) static void QOPENGLF_APIENTRY qopenglfResolveDepthRangef(GLclampf zNear, GLclampf zFar) { - if (QOpenGLContext::currentContext()->isES()) { + if (QOpenGLContext::currentContext()->isOpenGLES()) { RESOLVE_FUNC_VOID(0, DepthRangef)(zNear, zFar); } else { RESOLVE_FUNC_VOID(0, DepthRange)((GLdouble) zNear, (GLdouble) zFar); @@ -3174,15 +3168,7 @@ static void QOPENGLF_APIENTRY qopenglfResolveGetBufferSubData(GLenum target, qop (target, offset, size, data); } -#ifndef QT_OPENGL_ES_2 -// Desktop only - -static void QOPENGLF_APIENTRY qopenglfResolveGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) -{ - RESOLVE_FUNC_VOID(0, GetTexLevelParameteriv)(target, level, pname, params); -} - -#ifndef QT_OPENGL_DYNAMIC +#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_DYNAMIC) // Special translation functions for ES-specific calls on desktop GL static void QOPENGLF_APIENTRY qopenglfTranslateClearDepthf(GLclampf depth) @@ -3194,10 +3180,7 @@ static void QOPENGLF_APIENTRY qopenglfTranslateDepthRangef(GLclampf zNear, GLcla { ::glDepthRange(zNear, zFar); } - -#endif // QT_OPENGL_DYNAMIC - -#endif // QT_OPENGL_ES2 +#endif // !ES && !DYNAMIC QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *) { @@ -3256,8 +3239,6 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *) TexParameteriv = qopenglfResolveTexParameteriv; TexSubImage2D = qopenglfResolveTexSubImage2D; Viewport = qopenglfResolveViewport; - - GetTexLevelParameteriv = qopenglfResolveGetTexLevelParameteriv; } else { #ifndef QT_OPENGL_DYNAMIC // Use the functions directly. This requires linking QtGui to an OpenGL implementation. @@ -3301,15 +3282,17 @@ QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *) StencilFunc = ::glStencilFunc; StencilMask = ::glStencilMask; StencilOp = ::glStencilOp; - TexImage2D = ::glTexImage2D; +#if defined(Q_OS_OSX) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 + TexImage2D = reinterpret_cast(glTexImage2D); +#else + TexImage2D = glTexImage2D; +#endif TexParameterf = ::glTexParameterf; TexParameterfv = ::glTexParameterfv; TexParameteri = ::glTexParameteri; TexParameteriv = ::glTexParameteriv; TexSubImage2D = ::glTexSubImage2D; Viewport = ::glViewport; - - GetTexLevelParameteriv = ::glGetTexLevelParameteriv; #else // QT_OPENGL_DYNAMIC // This should not happen. qFatal("QOpenGLFunctions: Dynamic OpenGL builds do not support platforms with insufficient function resolving capabilities"); diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h index 03c12200d5..de1de39db2 100644 --- a/src/gui/opengl/qopenglfunctions.h +++ b/src/gui/opengl/qopenglfunctions.h @@ -407,9 +407,6 @@ public: void glVertexAttrib4fv(GLuint indx, const GLfloat* values); void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); - // OpenGL1, not GLES2 - void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params); - protected: QOpenGLFunctionsPrivate *d_ptr; static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; } @@ -565,9 +562,6 @@ struct QOpenGLFunctionsPrivate void (QOPENGLF_APIENTRYP VertexAttrib4fv)(GLuint indx, const GLfloat* values); void (QOPENGLF_APIENTRYP VertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); - // OpenGL1 only, not GLES2 - void (QOPENGLF_APIENTRYP GetTexLevelParameteriv)(GLenum target, GLint level, GLenum pname, GLint *params); - // Special non-ES OpenGL variants, not to be called directly void (QOPENGLF_APIENTRYP ClearDepth)(GLdouble depth); void (QOPENGLF_APIENTRYP DepthRange)(GLdouble zNear, GLdouble zFar); @@ -2154,24 +2148,6 @@ inline void QOpenGLFunctions::glVertexAttribPointer(GLuint indx, GLint size, GLe Q_OPENGL_FUNCTIONS_DEBUG } -// OpenGL1, not GLES2 - -inline void QOpenGLFunctions::glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) -{ -#ifdef QT_OPENGL_ES_2 - Q_UNUSED(target); - Q_UNUSED(level); - Q_UNUSED(pname); - Q_UNUSED(params); - // Cannot get here. - qFatal("QOpenGLFunctions: glGetTexLevelParameteriv not available with OpenGL ES"); -#else - Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); - d_ptr->GetTexLevelParameteriv(target, level, pname, params); -#endif - Q_OPENGL_FUNCTIONS_DEBUG -} - QT_END_NAMESPACE #endif // QT_NO_OPENGL diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index f160b340e0..81a0d82c99 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -221,7 +221,7 @@ void QOpenGL2PaintEngineExPrivate::updateBrushTexture() currentBrushPixmap = currentBrushPixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); GLuint wrapMode = GL_REPEAT; - if (QOpenGLContext::currentContext()->isES()) { + if (QOpenGLContext::currentContext()->isOpenGLES()) { // OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead, // we emulate GL_REPEAT by only taking the fractional part of the texture coords // in the qopenglslTextureBrushSrcFragmentShader program. @@ -598,7 +598,7 @@ void QOpenGL2PaintEngineExPrivate::resetGLState() setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false); setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { // gl_Color, corresponding to vertex attribute 3, may have been changed float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; funcs.glVertexAttrib4fv(3, color); @@ -1333,7 +1333,7 @@ void QOpenGL2PaintEngineEx::renderHintsChanged() state()->renderHintsChanged = true; #ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGL2PaintEngineEx); if ((state()->renderHints & QPainter::Antialiasing) || (state()->renderHints & QPainter::HighQualityAntialiasing)) @@ -2011,7 +2011,7 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) d->glyphCacheFormat = QFontEngine::Format_A8; #ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { d->funcs.glDisable(GL_MULTISAMPLE); d->glyphCacheFormat = QFontEngine::Format_A32; d->multisamplingAlwaysEnabled = false; diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index bfde270446..6e85e5eb4b 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -176,7 +176,7 @@ public: #endif { #ifndef QT_OPENGL_ES_2 - if (!ctx->isES()) { + if (!ctx->isOpenGLES()) { QSurfaceFormat f = ctx->format(); // Geometry shaders require OpenGL >= 3.2 @@ -445,7 +445,7 @@ bool QOpenGLShader::compileSourceCode(const char *source) #ifdef QOpenGL_REDEFINE_HIGHP if (d->shaderType == Fragment && !ctx_d->workaround_missingPrecisionQualifiers - && QOpenGLContext::currentContext()->isES()) { + && QOpenGLContext::currentContext()->isOpenGLES()) { src.append(redefineHighp); srclen.append(GLint(sizeof(redefineHighp) - 1)); } @@ -674,7 +674,7 @@ bool QOpenGLShaderProgram::init() #ifndef QT_OPENGL_ES_2 // Resolve OpenGL 4 functions for tessellation shader support QSurfaceFormat format = context->format(); - if (!context->isES() + if (!context->isOpenGLES() && format.version() >= qMakePair(4, 0)) { d->tessellationFuncs = context->versionFunctions(); d->tessellationFuncs->initializeOpenGLFunctions(); @@ -2236,6 +2236,10 @@ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& v Sets the uniform variable at \a location in the current context to a 2x3 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat2x3, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec3. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value) @@ -2251,6 +2255,10 @@ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value Sets the uniform variable called \a name in the current context to a 2x3 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat2x3, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec3. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value) @@ -2262,6 +2270,10 @@ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& v Sets the uniform variable at \a location in the current context to a 2x4 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat2x4, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec4. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value) @@ -2277,6 +2289,10 @@ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value Sets the uniform variable called \a name in the current context to a 2x4 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat2x4, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec4. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value) @@ -2288,6 +2304,10 @@ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& v Sets the uniform variable at \a location in the current context to a 3x2 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat3x2, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec2. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value) @@ -2303,6 +2323,10 @@ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value Sets the uniform variable called \a name in the current context to a 3x2 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat3x2, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec2. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value) @@ -2340,6 +2364,10 @@ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& v Sets the uniform variable at \a location in the current context to a 3x4 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat3x4, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec4. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value) @@ -2355,6 +2383,10 @@ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value Sets the uniform variable called \a name in the current context to a 3x4 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat3x4, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec4. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value) @@ -2366,6 +2398,10 @@ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& v Sets the uniform variable at \a location in the current context to a 4x2 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat4x2, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec2. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value) @@ -2381,6 +2417,10 @@ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value Sets the uniform variable called \a name in the current context to a 4x2 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat4x2, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec2. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value) @@ -2392,6 +2432,10 @@ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& v Sets the uniform variable at \a location in the current context to a 4x3 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat4x3, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec3. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value) @@ -2407,6 +2451,10 @@ void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value Sets the uniform variable called \a name in the current context to a 4x3 matrix \a value. + \note This function is not aware of non square matrix support, + that is, GLSL types like mat4x3, that is present in modern OpenGL + versions. Instead, it treats the uniform as an array of vec3. + \sa setAttributeValue() */ void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value) @@ -3280,7 +3328,7 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) #ifndef QT_OPENGL_ES_2 // Geometry shaders require OpenGL 3.2 or newer QSurfaceFormat format = context->format(); - return (!context->isES()) + return (!context->isOpenGLES()) && (format.version() >= qMakePair(3, 2)); #else // No geometry shader support in OpenGL ES2 @@ -3288,7 +3336,7 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) #endif } else if (type == TessellationControl || type == TessellationEvaluation) { #if !defined(QT_OPENGL_ES_2) - return (!context->isES()) + return (!context->isOpenGLES()) && (format.version() >= qMakePair(4, 0)); #else // No tessellation shader support in OpenGL ES2 diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index 078274eabd..e3444332a0 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -180,6 +180,10 @@ bool QOpenGLTexturePrivate::create() void QOpenGLTexturePrivate::destroy() { + if (!context) { + // not created or already destroyed + return; + } if (QOpenGLContext::currentContext() != context) { qWarning("Requires a valid current OpenGL context.\n" "Texture has not been destroyed"); @@ -2432,7 +2436,7 @@ bool QOpenGLTexture::hasFeature(Feature feature) bool supported = false; #if !defined(QT_OPENGL_ES_2) - if (!ctx->isES()) { + if (!ctx->isOpenGLES()) { switch (feature) { case ImmutableMultisampleStorage: case TextureBuffer: @@ -2489,7 +2493,7 @@ bool QOpenGLTexture::hasFeature(Feature feature) } } - if (ctx->isES()) + if (ctx->isOpenGLES()) #endif { switch (feature) { @@ -2524,7 +2528,7 @@ bool QOpenGLTexture::hasFeature(Feature feature) void QOpenGLTexture::setMipBaseLevel(int baseLevel) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->textureId); @@ -2561,7 +2565,7 @@ int QOpenGLTexture::mipBaseLevel() const void QOpenGLTexture::setMipMaxLevel(int maxLevel) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->textureId); @@ -2598,7 +2602,7 @@ int QOpenGLTexture::mipMaxLevel() const void QOpenGLTexture::setMipLevelRange(int baseLevel, int maxLevel) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->textureId); @@ -2708,7 +2712,7 @@ void QOpenGLTexture::generateMipMaps(int baseLevel, bool resetBaseLevel) void QOpenGLTexture::setSwizzleMask(SwizzleComponent component, SwizzleValue value) { #if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -2737,7 +2741,7 @@ void QOpenGLTexture::setSwizzleMask(SwizzleValue r, SwizzleValue g, SwizzleValue b, SwizzleValue a) { #if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -2786,7 +2790,7 @@ QOpenGLTexture::SwizzleValue QOpenGLTexture::swizzleMask(SwizzleComponent compon void QOpenGLTexture::setDepthStencilMode(QOpenGLTexture::DepthStencilMode mode) { #if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -2977,7 +2981,7 @@ QOpenGLTexture::WrapMode QOpenGLTexture::wrapMode(QOpenGLTexture::CoordinateDire void QOpenGLTexture::setBorderColor(QColor color) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -3007,7 +3011,7 @@ void QOpenGLTexture::setBorderColor(QColor color) void QOpenGLTexture::setBorderColor(float r, float g, float b, float a) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -3040,7 +3044,7 @@ void QOpenGLTexture::setBorderColor(float r, float g, float b, float a) void QOpenGLTexture::setBorderColor(int r, int g, int b, int a) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -3075,7 +3079,7 @@ void QOpenGLTexture::setBorderColor(int r, int g, int b, int a) void QOpenGLTexture::setBorderColor(uint r, uint g, uint b, uint a) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -3187,7 +3191,7 @@ void QOpenGLTexture::borderColor(unsigned int *border) const void QOpenGLTexture::setMinimumLevelOfDetail(float value) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -3224,7 +3228,7 @@ float QOpenGLTexture::minimumLevelOfDetail() const void QOpenGLTexture::setMaximumLevelOfDetail(float value) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -3260,7 +3264,7 @@ float QOpenGLTexture::maximumLevelOfDetail() const void QOpenGLTexture::setLevelOfDetailRange(float min, float max) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); @@ -3302,7 +3306,7 @@ QPair QOpenGLTexture::levelOfDetailRange() const void QOpenGLTexture::setLevelofDetailBias(float bias) { #if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { Q_D(QOpenGLTexture); d->create(); Q_ASSERT(d->texFuncs); diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp index 3287bbb972..ac88d9d3a5 100644 --- a/src/gui/opengl/qopengltextureglyphcache.cpp +++ b/src/gui/opengl/qopengltextureglyphcache.cpp @@ -369,7 +369,7 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed || mask.format() == QImage::Format_ARGB32_Premultiplied #else || (mask.format() == QImage::Format_ARGB32_Premultiplied - && ctx->isES()) + && ctx->isOpenGLES()) #endif ) { for (int y = 0; y < maskHeight; ++y) { @@ -387,7 +387,7 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed src[x] = qRgba(r, g, b, avg); // swizzle the bits to accommodate for the GL_RGBA upload. #if Q_BYTE_ORDER != Q_BIG_ENDIAN - if (ctx->isES()) + if (ctx->isOpenGLES()) #endif src[x] = ARGB2RGBA(src[x]); } @@ -400,7 +400,7 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed #ifdef QT_OPENGL_ES_2 GLenum fmt = GL_RGBA; #else - GLenum fmt = ctx->isES() ? GL_RGBA : GL_BGRA; + GLenum fmt = ctx->isOpenGLES() ? GL_RGBA : GL_BGRA; #endif // QT_OPENGL_ES_2 #if Q_BYTE_ORDER == Q_BIG_ENDIAN diff --git a/src/gui/opengl/qopengltexturehelper.cpp b/src/gui/opengl/qopengltexturehelper.cpp index 1d31fb5605..27aece8eca 100644 --- a/src/gui/opengl/qopengltexturehelper.cpp +++ b/src/gui/opengl/qopengltexturehelper.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) { // Resolve EXT_direct_state_access entry points if present - if (!context->isES() + if (!context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_EXT_direct_state_access"))) { TextureParameteriEXT = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glTextureParameteriEXT"))); TextureParameterivEXT = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glTextureParameterivEXT"))); @@ -121,7 +121,7 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) } // Some DSA functions are part of NV_texture_multisample instead - if (!context->isES() + if (!context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_NV_texture_multisample"))) { TextureImage3DMultisampleNV = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glTextureImage3DMultisampleNV"))); TextureImage2DMultisampleNV = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glTextureImage2DMultisampleNV"))); @@ -190,7 +190,7 @@ QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) TexSubImage1D = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glTexSubImage1D"))); #endif - if (context->isES() && context->hasExtension(QByteArrayLiteral("GL_OES_texture_3D"))) { + if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_OES_texture_3D"))) { TexImage3D = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glTexImage3DOES"))); TexSubImage3D = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glTexSubImage3DOES"))); CompressedTexImage3D = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glCompressedTexImage3DOES"))); diff --git a/src/gui/opengl/qopengltimerquery.cpp b/src/gui/opengl/qopengltimerquery.cpp index 908a9cee07..5159ec58fc 100644 --- a/src/gui/opengl/qopengltimerquery.cpp +++ b/src/gui/opengl/qopengltimerquery.cpp @@ -135,7 +135,7 @@ bool QOpenGLTimerQueryPrivate::create() return false; } - if (context->isES()) { + if (context->isOpenGLES()) { qWarning("QOpenGLTimerQuery: Not supported on OpenGL ES"); return false; } diff --git a/src/gui/opengl/qopenglvertexarrayobject.cpp b/src/gui/opengl/qopenglvertexarrayobject.cpp index 9dfd5b2a6f..5ebfc9a9c8 100644 --- a/src/gui/opengl/qopenglvertexarrayobject.cpp +++ b/src/gui/opengl/qopenglvertexarrayobject.cpp @@ -60,7 +60,7 @@ public: QVertexArrayObjectHelper(QOpenGLContext *context) { Q_ASSERT(context); - if (context->isES()) { + if (context->isOpenGLES()) { GenVertexArrays = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glGenVertexArraysOES"))); DeleteVertexArrays = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glDeleteVertexArraysOES"))); BindVertexArray = reinterpret_cast(context->getProcAddress(QByteArrayLiteral("glBindVertexArrayOES"))); @@ -159,7 +159,7 @@ bool QOpenGLVertexArrayObjectPrivate::create() context = ctx; QObject::connect(context, SIGNAL(aboutToBeDestroyed()), q, SLOT(_q_contextAboutToBeDestroyed())); - if (ctx->isES()) { + if (ctx->isOpenGLES()) { if (ctx->hasExtension(QByteArrayLiteral("GL_OES_vertex_array_object"))) { vaoFuncs.helper = new QVertexArrayObjectHelper(ctx); vaoFuncsType = OES; diff --git a/src/gui/painting/qblittable_p.h b/src/gui/painting/qblittable_p.h index 159e60079f..f65549d63c 100644 --- a/src/gui/painting/qblittable_p.h +++ b/src/gui/painting/qblittable_p.h @@ -68,7 +68,7 @@ public: // Internal ones OutlineCapability = 0x0001000 }; - Q_DECLARE_FLAGS (Capabilities, Capability); + Q_DECLARE_FLAGS (Capabilities, Capability) QBlittable(const QSize &size, Capabilities caps); virtual ~QBlittable(); diff --git a/src/gui/painting/qpaintengine_blitter.cpp b/src/gui/painting/qpaintengine_blitter.cpp index 26eacacd49..67a692e2db 100644 --- a/src/gui/painting/qpaintengine_blitter.cpp +++ b/src/gui/painting/qpaintengine_blitter.cpp @@ -238,7 +238,7 @@ private: class QBlitterPaintEnginePrivate : public QRasterPaintEnginePrivate { - Q_DECLARE_PUBLIC(QBlitterPaintEngine); + Q_DECLARE_PUBLIC(QBlitterPaintEngine) public: QBlitterPaintEnginePrivate(QBlittablePlatformPixmap *p) : QRasterPaintEnginePrivate() diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index bfcb24ae3a..ce8c1d1ca7 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -235,21 +235,6 @@ static const QRectF boundingRect(const QPointF *points, int pointCount) } #endif -template static inline bool isRect(const T *pts, int elementCount) { - return (elementCount == 5 // 5-point polygon, check for closed rect - && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point - && pts[0] == pts[6] && pts[2] == pts[4] // x values equal - && pts[1] == pts[3] && pts[5] == pts[7] // y values equal... - && pts[0] < pts[4] && pts[1] < pts[5] - ) || - (elementCount == 4 // 4-point polygon, check for unclosed rect - && pts[0] == pts[6] && pts[2] == pts[4] // x values equal - && pts[1] == pts[3] && pts[5] == pts[7] // y values equal... - && pts[0] < pts[4] && pts[1] < pts[5] - ); -} - - static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data) { ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y))); @@ -1193,22 +1178,14 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) Q_D(QRasterPaintEngine); QRasterPaintEngineState *s = state(); - const qreal *points = path.points(); - const QPainterPath::ElementType *types = path.elements(); - // There are some cases that are not supported by clip(QRect) if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) { if (s->matrix.type() <= QTransform::TxScale - && ((path.shape() == QVectorPath::RectangleHint) - || (isRect(points, path.elementCount()) - && (!types || (types[0] == QPainterPath::MoveToElement - && types[1] == QPainterPath::LineToElement - && types[2] == QPainterPath::LineToElement - && types[3] == QPainterPath::LineToElement))))) { + && path.isRect()) { #ifdef QT_DEBUG_DRAW qDebug() << " --- optimizing vector clip to rect clip..."; #endif - + const qreal *points = path.points(); QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]); if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op)) return; @@ -1939,7 +1916,7 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly #endif Q_ASSERT(pointCount >= 2); - if (mode != PolylineMode && isRect((qreal *) points, pointCount)) { + if (mode != PolylineMode && QVectorPath::isRect((qreal *) points, pointCount)) { QRectF r(points[0], points[2]); drawRects(&r, 1); return; @@ -1980,7 +1957,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg qDebug() << " - " << points[i]; #endif Q_ASSERT(pointCount >= 2); - if (mode != PolylineMode && isRect((int *) points, pointCount)) { + if (mode != PolylineMode && QVectorPath::isRect((int *) points, pointCount)) { QRect r(points[0].x(), points[0].y(), points[2].x() - points[0].x(), diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 6425aa065e..5b6c4bb83d 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -314,7 +314,7 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu funcs->glGenTextures(1, &d_ptr->textureId); funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); #ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); } diff --git a/src/gui/painting/qvectorpath_p.h b/src/gui/painting/qvectorpath_p.h index e97d6e1dce..ca95c32597 100644 --- a/src/gui/painting/qvectorpath_p.h +++ b/src/gui/painting/qvectorpath_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -167,6 +167,32 @@ public: return 0; } + template static inline bool isRect(const T *pts, int elementCount) { + return (elementCount == 5 // 5-point polygon, check for closed rect + && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point + && pts[0] == pts[6] && pts[2] == pts[4] // x values equal + && pts[1] == pts[3] && pts[5] == pts[7] // y values equal... + && pts[0] < pts[4] && pts[1] < pts[5] + ) || + (elementCount == 4 // 4-point polygon, check for unclosed rect + && pts[0] == pts[6] && pts[2] == pts[4] // x values equal + && pts[1] == pts[3] && pts[5] == pts[7] // y values equal... + && pts[0] < pts[4] && pts[1] < pts[5] + ); + } + + inline bool isRect() const + { + const QPainterPath::ElementType * const types = elements(); + + return (shape() == QVectorPath::RectangleHint) + || (isRect(points(), elementCount()) + && (!types || (types[0] == QPainterPath::MoveToElement + && types[1] == QPainterPath::LineToElement + && types[2] == QPainterPath::LineToElement + && types[3] == QPainterPath::LineToElement))); + } + private: Q_DISABLE_COPY(QVectorPath) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 35950c709b..34788dc4dc 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -122,20 +122,9 @@ private: return; const int end = start + length; for (int i = start + 1; i < end; ++i) { - // According to the unicode spec we should be treating characters in the Common script - // (punctuation, spaces, etc) as being the same script as the surrounding text for the - // purpose of splitting up text. This is important because, for example, a fullstop - // (0x2E) can be used to indicate an abbreviation and so must be treated as part of a - // word. Thus it must be passed along with the word in languages that have to calculate - // word breaks. For example the thai word "ครม." has no word breaks but the word "ครม" - // does. - // Unfortuntely because we split up the strings for both wordwrapping and for setting - // the font and because Japanese and Chinese are also aliases of the script "Common", - // doing this would break too many things. So instead we only pass the full stop - // along, and nothing else. if (m_analysis[i].bidiLevel == m_analysis[start].bidiLevel && m_analysis[i].flags == m_analysis[start].flags - && (m_analysis[i].script == m_analysis[start].script || m_string[i] == QLatin1Char('.')) + && m_analysis[i].script == m_analysis[start].script && m_analysis[i].flags < QScriptAnalysis::SpaceTabOrObject && i - start < MaxItemLength) continue; @@ -1515,26 +1504,22 @@ void QTextEngine::itemize() const while (uc < e) { switch (*uc) { case QChar::ObjectReplacementCharacter: - analysis->script = QChar::Script_Common; analysis->flags = QScriptAnalysis::Object; break; case QChar::LineSeparator: if (analysis->bidiLevel % 2) --analysis->bidiLevel; - analysis->script = QChar::Script_Common; analysis->flags = QScriptAnalysis::LineOrParagraphSeparator; if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) *const_cast(uc) = 0x21B5; // visual line separator break; case QChar::Tabulation: - analysis->script = QChar::Script_Common; analysis->flags = QScriptAnalysis::Tab; analysis->bidiLevel = control.baseLevel(); break; case QChar::Space: case QChar::Nbsp: if (option.flags() & QTextOption::ShowTabsAndSpaces) { - analysis->script = QChar::Script_Common; analysis->flags = QScriptAnalysis::Space; analysis->bidiLevel = control.baseLevel(); break; @@ -1556,8 +1541,10 @@ void QTextEngine::itemize() const #ifdef QT_ENABLE_HARFBUZZ_NG analysis = scriptAnalysis.data(); if (useHarfbuzzNG) { + // ### pretend HB-old behavior for now for (int i = 0; i < length; ++i) { switch (analysis[i].script) { + case QChar::Script_Latin: case QChar::Script_Han: case QChar::Script_Hiragana: case QChar::Script_Katakana: diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 7b5ad1e2f1..8743989dec 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -352,8 +352,10 @@ void QHttpThreadDelegate::startRequest() connect(httpReply, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)), this, SLOT(synchronousAuthenticationRequiredSlot(QHttpNetworkRequest,QAuthenticator*))); +#ifndef QT_NO_NETWORKPROXY connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), this, SLOT(synchronousProxyAuthenticationRequiredSlot(QNetworkProxy,QAuthenticator*))); +#endif // Don't care about ignored SSL errors for now in the synchronous HTTP case. } else if (!synchronous) { @@ -373,8 +375,10 @@ void QHttpThreadDelegate::startRequest() // Connect the reply signals that we can directly forward connect(httpReply, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)), this, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*))); +#ifndef QT_NO_NETWORKPROXY connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); +#endif } connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)), @@ -706,9 +710,11 @@ void QHttpThreadDelegate::synchronousProxyAuthenticationRequiredSlot(const QNet a->setPassword(credential.password); } +#ifndef QT_NO_NETWORKPROXY // Disconnect this connection now since we only want to ask the authentication cache once. QObject::disconnect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), this, SLOT(synchronousProxyAuthenticationRequiredSlot(QNetworkProxy,QAuthenticator*))); +#endif } #endif diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 1ceec717c6..b8f76f8d4f 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -748,7 +748,7 @@ bool QAbstractSocketPrivate::canReadNotification() return true; } - if (isBuffered && socketEngine) + if ((isBuffered || socketType != QAbstractSocket::TcpSocket) && socketEngine) socketEngine->setReadNotificationEnabled(readBufferMaxSize == 0 || readBufferMaxSize > q->bytesAvailable()); // reset the read socket notifier state if we reentered inside the diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp index 4b2d1c372e..db1d3dc96b 100644 --- a/src/network/socket/qnativesocketengine_winrt.cpp +++ b/src/network/socket/qnativesocketengine_winrt.cpp @@ -74,6 +74,7 @@ typedef ITypedEventHandler DatagramReceivedHandler; typedef IAsyncOperationWithProgressCompletedHandler SocketReadCompletedHandler; typedef IAsyncOperationWithProgressCompletedHandler SocketWriteCompletedHandler; +typedef IAsyncOperationWithProgress IAsyncBufferOperation; QT_BEGIN_NAMESPACE @@ -130,6 +131,8 @@ QString qt_QStringFromHSTRING(HSTRING string) return QString::fromWCharArray(rawString, length); } +#define READ_BUFFER_SIZE 8192 + class ByteArrayBuffer : public Microsoft::WRL::RuntimeClass, IBuffer, Windows::Storage::Streams::IBufferByteAccess> { @@ -167,16 +170,6 @@ public: return S_OK; } - QNativeSocketEngine *engine() const - { - return m_engine; - } - - void setEngine(QNativeSocketEngine *engine) - { - m_engine = engine; - } - ComPtr inputStream() const { return m_stream; @@ -190,13 +183,33 @@ public: private: QByteArray m_bytes; UINT32 m_length; - QPointer m_engine; ComPtr m_stream; }; +template +static AsyncStatus opStatus(const ComPtr &op) +{ + ComPtr info; + HRESULT hr = op.As(&info); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to cast op to IAsyncInfo."); + return Error; + } + AsyncStatus status; + hr = info->get_Status(&status); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get AsyncStatus."); + return Error; + } + return status; +} + QNativeSocketEngine::QNativeSocketEngine(QObject *parent) : QAbstractSocketEngine(*new QNativeSocketEnginePrivate(), parent) { + connect(this, SIGNAL(connectionReady()), SLOT(connectionNotification()), Qt::QueuedConnection); + connect(this, SIGNAL(readReady()), SLOT(readNotification()), Qt::QueuedConnection); + connect(this, SIGNAL(writeReady()), SLOT(writeNotification()), Qt::QueuedConnection); } QNativeSocketEngine::~QNativeSocketEngine() @@ -230,7 +243,7 @@ bool QNativeSocketEngine::initialize(qintptr socketDescriptor, QAbstractSocket:: // Currently, only TCP sockets are initialized this way. SocketHandler *handler = gSocketHandler(); - d->tcp = handler->pendingTcpSockets.value(socketDescriptor, Q_NULLPTR); + d->tcp = handler->pendingTcpSockets.take(socketDescriptor); d->socketType = QAbstractSocket::TcpSocket; if (!d->tcp || !d->fetchConnectionParameters()) @@ -271,23 +284,33 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port) return false; } + ComPtr op; const QString portString = QString::number(port); HStringReference portReference(reinterpret_cast(portString.utf16())); - ComPtr action; HRESULT hr = E_FAIL; if (d->socketType == QAbstractSocket::TcpSocket) - hr = d->tcp->ConnectAsync(remoteHost.Get(), portReference.Get(), &action); + hr = d->tcp->ConnectAsync(remoteHost.Get(), portReference.Get(), &op); else if (d->socketType == QAbstractSocket::UdpSocket) - hr = d->udp->ConnectAsync(remoteHost.Get(), portReference.Get(), &action); + hr = d->udp->ConnectAsync(remoteHost.Get(), portReference.Get(), &op); if (FAILED(hr)) { qWarning("QNativeSocketEnginePrivate::nativeConnect:: Could not obtain connect action"); return false; } - action->put_Completed(Callback(&QNativeSocketEnginePrivate::interruptEventDispatcher).Get()); - hr = action->GetResults(); - while ((hr = action->GetResults()) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents); + hr = op->put_Completed(Callback( + d, &QNativeSocketEnginePrivate::handleConnectToHost).Get()); + if (FAILED(hr)) { + qErrnoWarning(hr, "Unable to set host connection callback."); + return false; + } + d->socketState = QAbstractSocket::ConnectingState; + while (opStatus(op) == Started) + d->eventLoop.processEvents(); + + AsyncStatus status = opStatus(op); + if (status == Error || status == Canceled) + return false; + if (hr == 0x8007274c) { // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. d->setError(QAbstractSocket::NetworkError, d->ConnectionTimeOutErrorString); d->socketState = QAbstractSocket::UnconnectedState; @@ -305,24 +328,21 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port) } if (d->socketType == QAbstractSocket::TcpSocket) { - UINT32 capacity; - hr = d->inputBuffer->get_Capacity(&capacity); - if (FAILED(hr)) - return false; IInputStream *stream; hr = d->tcp->get_InputStream(&stream); if (FAILED(hr)) return false; - ByteArrayBuffer *buffer = static_cast(d->inputBuffer.Get()); - buffer->setEngine(this); + ByteArrayBuffer *buffer = static_cast(d->readBuffer.Get()); buffer->setInputStream(stream); - ComPtr> op; - hr = stream->ReadAsync(buffer, capacity, InputStreamOptions_Partial, &op); + ComPtr op; + hr = stream->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op); if (FAILED(hr)) return false; - hr = op->put_Completed(Callback(&QNativeSocketEnginePrivate::handleReadyRead).Get()); - if (FAILED(hr)) + hr = op->put_Completed(Callback(d, &QNativeSocketEnginePrivate::handleReadyRead).Get()); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to set socket read callback."); return false; + } } d->socketState = QAbstractSocket::ConnectedState; return true; @@ -358,21 +378,35 @@ bool QNativeSocketEngine::bind(const QHostAddress &address, quint16 port) d->tcpListener->add_ConnectionReceived(Callback(d, &QNativeSocketEnginePrivate::handleClientConnection).Get(), &token); hr = d->tcpListener->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op); if (FAILED(hr)) { - qWarning("Unable to bind"); // ### Set error message + qErrnoWarning(hr, "Unable to bind socket."); // ### Set error message return false; } } else if (d->socketType == QAbstractSocket::UdpSocket) { hr = d->udp->BindEndpointAsync(hostAddress.Get(), portString.Get(), &op); if (FAILED(hr)) { - qWarning("unable to bind"); // ### Set error message + qErrnoWarning(hr, "Unable to bind socket."); // ### Set error message + return false; + } + hr = op->put_Completed(Callback(d, &QNativeSocketEnginePrivate::handleBindCompleted).Get()); + if (FAILED(hr)) { + qErrnoWarning(hr, "Unable to set bind callback."); return false; } } if (op) { - // Wait for connection to enter bound state - TODO: timeout, check result - while ((hr = op->GetResults()) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(); + while (opStatus(op) == Started) + d->eventLoop.processEvents(); + + AsyncStatus status = opStatus(op); + if (status == Error || status == Canceled) + return false; + + hr = op->GetResults(); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to bind socket"); + return false; + } d->socketState = QAbstractSocket::BoundState; d->fetchConnectionParameters(); @@ -410,17 +444,22 @@ int QNativeSocketEngine::accept() if (d->socketType == QAbstractSocket::TcpSocket) { IStreamSocket *socket = d->pendingConnections.takeFirst(); - UINT32 capacity; - d->inputBuffer->get_Capacity(&capacity); IInputStream *stream; socket->get_InputStream(&stream); // TODO: delete buffer and stream on socket close - ByteArrayBuffer *buffer = static_cast(d->inputBuffer.Get()); - buffer->setEngine(this); + ByteArrayBuffer *buffer = static_cast(d->readBuffer.Get()); buffer->setInputStream(stream); - ComPtr> op; - stream->ReadAsync(buffer, capacity, InputStreamOptions_Partial, &op); - op->put_Completed(Callback(&QNativeSocketEnginePrivate::handleReadyRead).Get()); + ComPtr op; + HRESULT hr = stream->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op); + if (FAILED(hr)) { + qErrnoWarning(hr, "Faild to read from the socket buffer."); + return -1; + } + hr = op->put_Completed(Callback(d, &QNativeSocketEnginePrivate::handleReadyRead).Get()); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to set socket read callback."); + return -1; + } d->currentConnections.append(socket); SocketHandler *handler = gSocketHandler(); @@ -445,7 +484,6 @@ void QNativeSocketEngine::close() d->closingDown = true; socket->Close(); socket->Release(); - closeNotification(); d->socketDescriptor = -1; } d->socketDescriptor = -1; @@ -493,13 +531,7 @@ qint64 QNativeSocketEngine::bytesAvailable() const if (d->socketType != QAbstractSocket::TcpSocket) return -1; - if (d->inputBuffer) { - UINT32 len; - d->inputBuffer->get_Length(&len); - return len; - } - - return -1; + return d->readBytes.size() - d->readBytes.pos(); } qint64 QNativeSocketEngine::read(char *data, qint64 maxlen) @@ -508,54 +540,56 @@ qint64 QNativeSocketEngine::read(char *data, qint64 maxlen) if (d->socketType != QAbstractSocket::TcpSocket) return -1; - ComPtr dataReaderStatics; - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(), &dataReaderStatics); - ComPtr reader; - - dataReaderStatics->FromBuffer(d->inputBuffer.Get(), &reader); - - UINT32 bufferCapacity; - d->inputBuffer->get_Capacity(&bufferCapacity); - qint64 lengthToRead = maxlen < bufferCapacity ? maxlen : bufferCapacity; - - UINT32 bufferLength; - d->inputBuffer->get_Length(&bufferLength); - - lengthToRead = bufferLength < lengthToRead ? bufferLength : lengthToRead; - reader->ReadBytes(lengthToRead, (unsigned char*)data); - return lengthToRead; -} - -template -static qint64 nativeWrite(T *socket, const char *data, qint64 len) -{ - ComPtr stream; - HRESULT hr = socket->get_OutputStream(&stream); - if (FAILED(hr)) - return -1; - ComPtr buffer = Make(data, len); - ComPtr> op; - hr = stream->WriteAsync(buffer.Get(), &op); - if (FAILED(hr)) - return -1; - UINT32 bytesWritten; - while ((hr = op->GetResults(&bytesWritten)) == E_ILLEGAL_METHOD_CALL) - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - return bytesWritten; + QMutexLocker mutexLocker(&d->readMutex); + return d->readBytes.read(data, maxlen); } qint64 QNativeSocketEngine::write(const char *data, qint64 len) { Q_D(QNativeSocketEngine); - qint64 bytesWritten = -1; + HRESULT hr = E_FAIL; + ComPtr stream; if (d->socketType == QAbstractSocket::TcpSocket) - bytesWritten = nativeWrite(d->tcp, data, len); + hr = d->tcp->get_OutputStream(&stream); else if (d->socketType == QAbstractSocket::UdpSocket) - bytesWritten = nativeWrite(d->udp, data, len); - if (bytesWritten != -1 && d->notifyOnWrite) - writeNotification(); - return bytesWritten; + hr = d->udp->get_OutputStream(&stream); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get output stream to socket."); + return -1; + } + ComPtr buffer = Make(data, len); + ComPtr> op; + hr = stream->WriteAsync(buffer.Get(), &op); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to write to socket."); + return -1; + } + hr = op->put_Completed(Callback>( + d, &QNativeSocketEnginePrivate::handleWriteCompleted).Get()); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to set socket write callback."); + return -1; + } + + while (opStatus(op) == Started) + d->eventLoop.processEvents(); + + AsyncStatus status = opStatus(op); + if (status == Error || status == Canceled) + return -1; + + UINT32 bytesWritten; + hr = op->GetResults(&bytesWritten); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get written socket length."); + return -1; + } + + if (bytesWritten && d->notifyOnWrite) + emit writeReady(); + + return bytesWritten; } qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr, quint16 *port) @@ -698,7 +732,7 @@ bool QNativeSocketEngine::setOption(QAbstractSocketEngine::SocketOption option, bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) { - Q_D(const QNativeSocketEngine); + Q_D(QNativeSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false); Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForRead(), QAbstractSocket::UnconnectedState, false); @@ -714,14 +748,12 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut) return true; // If we are a client, we are ready to read if our buffer has data - UINT32 length; - if (FAILED(d->inputBuffer->get_Length(&length))) - return false; - if (length) + QMutexLocker locker(&d->readMutex); + if (!d->readBytes.atEnd()) return true; // Nothing to do, wait for more events - QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents|QEventLoop::WaitForMoreEvents); + d->eventLoop.processEvents(); } d->setError(QAbstractSocket::SocketTimeoutError, @@ -832,8 +864,8 @@ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() , closingDown(false) , socketDescriptor(-1) { - ComPtr buffer = Make(8192); - inputBuffer = buffer; + ComPtr buffer = Make(READ_BUFFER_SIZE); + readBuffer = buffer; } QNativeSocketEnginePrivate::~QNativeSocketEnginePrivate() @@ -1119,6 +1151,11 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() return true; } +HRESULT QNativeSocketEnginePrivate::handleBindCompleted(IAsyncAction *, AsyncStatus) +{ + return S_OK; +} + HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener *listener, IStreamSocketListenerConnectionReceivedEventArgs *args) { Q_Q(QNativeSocketEngine); @@ -1126,47 +1163,91 @@ HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener IStreamSocket *socket; args->get_Socket(&socket); pendingConnections.append(socket); - q->connectionNotification(); - q->readNotification(); - return interruptEventDispatcher(0, Completed); + emit q->connectionReady(); + emit q->readReady(); + return S_OK; } -HRESULT QNativeSocketEnginePrivate::interruptEventDispatcher(IAsyncAction *, AsyncStatus) +HRESULT QNativeSocketEnginePrivate::handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus) { - if (QThread *thread = QThread::currentThread()) { - if (QAbstractEventDispatcher *dispatcher = thread->eventDispatcher()) - dispatcher->interrupt(); + return S_OK; +} + +HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status) +{ + Q_Q(QNativeSocketEngine); + if (wasDeleted || isDeletingChildren) + return S_OK; + + if (status == Error || status == Canceled) + return S_OK; + + ByteArrayBuffer *buffer = 0; + HRESULT hr = asyncInfo->GetResults((IBuffer **)&buffer); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get ready read results."); + return S_OK; + } + UINT32 len; + buffer->get_Length(&len); + if (!len) { + if (q->isReadNotificationEnabled()) + emit q->readReady(); + return S_OK; + } + + byte *data; + buffer->Buffer(&data); + + readMutex.lock(); + if (readBytes.atEnd()) // Everything has been read; the buffer is safe to reset + readBytes.close(); + if (!readBytes.isOpen()) + readBytes.open(QBuffer::ReadWrite|QBuffer::Truncate); + qint64 readPos = readBytes.pos(); + readBytes.seek(readBytes.size()); + Q_ASSERT(readBytes.atEnd()); + readBytes.write(reinterpret_cast(data), qint64(len)); + readBytes.seek(readPos); + readMutex.unlock(); + + if (q->isReadNotificationEnabled()) + emit q->readReady(); + + ComPtr op; + hr = buffer->inputStream()->ReadAsync(buffer, READ_BUFFER_SIZE, InputStreamOptions_Partial, &op); + if (FAILED(hr)) { + qErrnoWarning(hr, "Could not read into socket stream buffer."); + return S_OK; + } + hr = op->put_Completed(Callback(this, &QNativeSocketEnginePrivate::handleReadyRead).Get()); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to set socket read callback."); + return S_OK; } return S_OK; } -HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncOperationWithProgress *asyncInfo, AsyncStatus) +HRESULT QNativeSocketEnginePrivate::handleWriteCompleted(IAsyncOperationWithProgress *op, AsyncStatus status) { - ByteArrayBuffer *buffer = 0; - HRESULT hr = asyncInfo->GetResults((IBuffer **)&buffer); - if (FAILED(hr)) - return hr; - UINT32 len; - buffer->get_Length(&len); - QNativeSocketEngine *q = buffer->engine(); - if (!q) + if (status == Error) { + ComPtr info; + HRESULT hr = op->QueryInterface(IID_PPV_ARGS(&info)); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to cast operation."); + return S_OK; + } + HRESULT errorCode; + hr = info->get_ErrorCode(&errorCode); + if (FAILED(hr)) { + qErrnoWarning(hr, "Failed to get error code."); + return S_OK; + } + qErrnoWarning(errorCode, "A socket error occurred."); return S_OK; - if (len > 0 && q->isReadNotificationEnabled()) { - q->readNotification(); } - // Continue reading ### TODO: read into offset!!! - UINT32 capacity; - buffer->get_Capacity(&capacity); - ComPtr> op; - if (SUCCEEDED(buffer->inputStream()->ReadAsync(buffer, capacity, InputStreamOptions_Partial, &op))) { - if (q) - return op->put_Completed(Callback(&QNativeSocketEnginePrivate::handleReadyRead).Get()); - else - return op->put_Completed(nullptr); - } - - return E_FAIL; + return S_OK; } HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, IDatagramSocketMessageReceivedEventArgs *args) @@ -1174,7 +1255,7 @@ HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, I Q_Q(QNativeSocketEngine); Q_ASSERT(udp == socket); pendingDatagrams.append(args); - q->readNotification(); + emit q->readReady(); return S_OK; } diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h index b5be5fa830..ec2e1b3ad4 100644 --- a/src/network/socket/qnativesocketengine_winrt_p.h +++ b/src/network/socket/qnativesocketengine_winrt_p.h @@ -52,6 +52,8 @@ // // We mean it. // +#include +#include #include "QtNetwork/qhostaddress.h" #include "private/qabstractsocketengine_p.h" #include @@ -127,6 +129,11 @@ public: bool isExceptionNotificationEnabled() const; void setExceptionNotificationEnabled(bool enable); +signals: + void connectionReady(); + void readReady(); + void writeReady(); + private: Q_DECLARE_PRIVATE(QNativeSocketEngine) Q_DISABLE_COPY(QNativeSocketEngine) @@ -191,17 +198,22 @@ private: ABI::Windows::Networking::Sockets::IDatagramSocket *udp; }; Microsoft::WRL::ComPtr tcpListener; - Microsoft::WRL::ComPtr inputBuffer; + Microsoft::WRL::ComPtr readBuffer; + QBuffer readBytes; + QMutex readMutex; QList pendingDatagrams; QList pendingConnections; QList currentConnections; + QEventLoop eventLoop; + HRESULT handleBindCompleted(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus); HRESULT handleNewDatagram(ABI::Windows::Networking::Sockets::IDatagramSocket *socket, ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs *args); HRESULT handleClientConnection(ABI::Windows::Networking::Sockets::IStreamSocketListener *tcpListener, ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args); - static HRESULT interruptEventDispatcher(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus); - static HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress *asyncInfo, ABI::Windows::Foundation::AsyncStatus); + HRESULT handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus); + HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress *asyncInfo, ABI::Windows::Foundation::AsyncStatus); + HRESULT handleWriteCompleted(ABI::Windows::Foundation::IAsyncOperationWithProgress *, ABI::Windows::Foundation::AsyncStatus); }; QT_END_NAMESPACE diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 52d8577abe..1b0c5afa00 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1470,8 +1470,10 @@ void QSslSocketBackendPrivate::continueHandshake() if (readBufferMaxSize) plainSocket->setReadBufferSize(readBufferMaxSize); +#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) if (q_SSL_ctrl((ssl), SSL_CTRL_GET_SESSION_REUSED, 0, NULL)) configuration.peerSessionShared = true; +#endif #ifdef QT_DECRYPT_SSL_TRAFFIC if (ssl->session && ssl->s3) { diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index f266318ba6..19e453e783 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -163,7 +163,7 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader; code[CustomImageSrcFragmentShader] = qglslCustomSrcFragmentShader; // Calls "customShader", which must be appended code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader; - if (!context->contextHandle()->isES()) + if (!context->contextHandle()->isOpenGLES()) code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader_desktop; else code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader_ES; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 162ae9fe79..5045d4a2ae 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -227,11 +227,19 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() if (currentBrushPixmap.width() > max_texture_size || currentBrushPixmap.height() > max_texture_size) currentBrushPixmap = currentBrushPixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + GLuint wrapMode = GL_REPEAT; + if (ctx->contextHandle()->isOpenGLES()) { + // OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead, + // we emulate GL_REPEAT by only taking the fractional part of the texture coords + // in the qopenglslTextureBrushSrcFragmentShader program. + wrapMode = GL_CLAMP_TO_EDGE; + } + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); QGLTexture *tex = ctx->d_func()->bindTexture(currentBrushPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption | QGLContext::CanFlipNativePixmapBindOption); - updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); + updateTextureFilter(GL_TEXTURE_2D, wrapMode, q->state()->renderHints & QPainter::SmoothPixmapTransform); textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1; } brushTextureDirty = false; @@ -543,7 +551,7 @@ void QGL2PaintEngineEx::beginNativePainting() d->glDisableVertexAttribArray(i); #ifndef QT_OPENGL_ES_2 - if (!d->ctx->contextHandle()->isES()) { + if (!d->ctx->contextHandle()->isOpenGLES()) { const QGLContext *ctx = d->ctx; const QGLFormat &fmt = d->device->format(); if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1) @@ -604,7 +612,7 @@ void QGL2PaintEngineExPrivate::resetGLState() ctx->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false); ctx->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); #ifndef QT_OPENGL_ES_2 - if (!ctx->contextHandle()->isES()) { + if (!ctx->contextHandle()->isOpenGLES()) { // gl_Color, corresponding to vertex attribute 3, may have been changed float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glVertexAttrib4fv(3, color); @@ -1371,7 +1379,7 @@ void QGL2PaintEngineEx::renderHintsChanged() state()->renderHintsChanged = true; #if !defined(QT_OPENGL_ES_2) - if (!d->ctx->contextHandle()->isES()) { + if (!d->ctx->contextHandle()->isOpenGLES()) { if ((state()->renderHints & QPainter::Antialiasing) || (state()->renderHints & QPainter::HighQualityAntialiasing)) d->glEnable(GL_MULTISAMPLE); @@ -2047,14 +2055,14 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->glDisable(GL_SCISSOR_TEST); #if !defined(QT_OPENGL_ES_2) - if (!d->ctx->contextHandle()->isES()) + if (!d->ctx->contextHandle()->isOpenGLES()) d->glDisable(GL_MULTISAMPLE); #endif d->glyphCacheFormat = QFontEngine::Format_A8; #if !defined(QT_OPENGL_ES_2) - if (!d->ctx->contextHandle()->isES()) { + if (!d->ctx->contextHandle()->isOpenGLES()) { d->glyphCacheFormat = QFontEngine::Format_A32; d->multisamplingAlwaysEnabled = false; } else { diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 01dfb38857..aa1d7decdb 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -320,7 +320,7 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed sub uchar g = src[x] >> 8; uchar b = src[x]; quint32 avg = (quint32(r) + quint32(g) + quint32(b) + 1) / 3; // "+1" for rounding. - if (ctx->contextHandle()->isES()) { + if (ctx->contextHandle()->isOpenGLES()) { // swizzle the bits to accommodate for the GL_RGBA upload. src[x] = (avg << 24) | (quint32(r) << 0) | (quint32(g) << 8) | (quint32(b) << 16); } else { @@ -334,7 +334,7 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed sub if (mask.format() == QImage::Format_RGB32) { GLenum format = GL_RGBA; #if !defined(QT_OPENGL_ES_2) - if (!ctx->contextHandle()->isES()) + if (!ctx->contextHandle()->isOpenGLES()) format = GL_BGRA; #endif funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, format, GL_UNSIGNED_BYTE, mask.bits()); diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index f4bf8fd68b..f033b51edd 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1719,7 +1719,7 @@ QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alp int w = size.width(); int h = size.height(); #ifndef QT_OPENGL_ES - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { qgl1_functions()->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); } @@ -2305,7 +2305,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G funcs->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filtering); QOpenGLContext *ctx = QOpenGLContext::currentContext(); - bool genMipmap = !ctx->isES(); + bool genMipmap = !ctx->isOpenGLES(); if (glFormat.directRendering() && (qgl_extensions()->hasOpenGLExtension(QOpenGLExtensions::GenerateMipmap)) && target == GL_TEXTURE_2D @@ -2447,7 +2447,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G printf(" - did byte swapping (%d ms)\n", time.elapsed()); #endif } - if (ctx->isES()) { + if (ctx->isOpenGLES()) { // OpenGL/ES requires that the internal and external formats be // identical. internalFormat = externalFormat; @@ -2460,7 +2460,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G const QImage &constRef = img; // to avoid detach in bits()... funcs->glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat, pixel_type, constRef.bits()); - if (genMipmap && ctx->isES()) + if (genMipmap && ctx->isOpenGLES()) q->functions()->glGenerateMipmap(target); #ifndef QT_NO_DEBUG GLenum error = funcs->glGetError(); @@ -2517,7 +2517,19 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, } if (!texture) { - QImage image = pixmap.toImage(); + QImage image; + QPaintEngine* paintEngine = pixmap.paintEngine(); + if (!paintEngine || paintEngine->type() != QPaintEngine::Raster) + image = pixmap.toImage(); + else { + // QRasterPixmapData::toImage() will deep-copy the backing QImage if there's an active QPainter on it. + // For performance reasons, we don't want that here, so we temporarily redirect the paint engine. + QPaintDevice* currentPaintDevice = paintEngine->paintDevice(); + paintEngine->setPaintDevice(0); + image = pixmap.toImage(); + paintEngine->setPaintDevice(currentPaintDevice); + } + // If the system depth is 16 and the pixmap doesn't have an alpha channel // then we convert it to RGB16 in the hope that it gets uploaded as a 16 // bit texture which is much faster to access than a 32-bit one. @@ -2545,7 +2557,7 @@ int QGLContextPrivate::maxTextureSize() #ifndef QT_OPENGL_ES Q_Q(QGLContext); - if (!q->contextHandle()->isES()) { + if (!q->contextHandle()->isOpenGLES()) { GLenum proxy = GL_PROXY_TEXTURE_2D; GLint size; @@ -2725,7 +2737,7 @@ static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint tex Q_UNUSED(textureHeight); Q_UNUSED(textureTarget); #else - if (textureTarget != GL_TEXTURE_2D && !QOpenGLContext::currentContext()->isES()) { + if (textureTarget != GL_TEXTURE_2D && !QOpenGLContext::currentContext()->isOpenGLES()) { if (textureWidth == -1 || textureHeight == -1) { QOpenGLFunctions_1_1 *gl1funcs = qgl1_functions(); gl1funcs->glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth); @@ -2795,7 +2807,7 @@ void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum text #ifndef QT_OPENGL_ES_2 QOpenGLFunctions *funcs = qgl_functions(); - if (!contextHandle()->isES()) { + if (!contextHandle()->isOpenGLES()) { #ifdef QT_OPENGL_ES if (textureTarget != GL_TEXTURE_2D) { qWarning("QGLContext::drawTexture(): texture target must be GL_TEXTURE_2D on OpenGL ES"); @@ -2857,7 +2869,7 @@ void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum text Q_UNUSED(textureId); Q_UNUSED(textureTarget); #else - if (!contextHandle()->isES()) { + if (!contextHandle()->isOpenGLES()) { QOpenGLFunctions *funcs = qgl_functions(); const bool wasEnabled = funcs->glIsEnabled(GL_TEXTURE_2D); GLint oldTexture; @@ -4163,7 +4175,7 @@ void QGLWidget::glDraw() return; makeCurrent(); #ifndef QT_OPENGL_ES - if (d->glcx->deviceIsPixmap() && !d->glcx->contextHandle()->isES()) + if (d->glcx->deviceIsPixmap() && !d->glcx->contextHandle()->isOpenGLES()) qgl1_functions()->glDrawBuffer(GL_FRONT); #endif QSize readback_target_size = d->glcx->d_ptr->readback_target_size; @@ -4208,7 +4220,7 @@ void QGLWidget::qglColor(const QColor& c) const #else Q_D(const QGLWidget); const QGLContext *ctx = QGLContext::currentContext(); - if (ctx && !ctx->contextHandle()->isES()) { + if (ctx && !ctx->contextHandle()->isOpenGLES()) { if (ctx->format().rgba()) qgl1_functions()->glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF()); else if (!d->cmap.isEmpty()) { // QGLColormap in use? @@ -4240,7 +4252,7 @@ void QGLWidget::qglClearColor(const QColor& c) const #else Q_D(const QGLWidget); const QGLContext *ctx = QGLContext::currentContext(); - if (ctx && !ctx->contextHandle()->isES()) { + if (ctx && !ctx->contextHandle()->isOpenGLES()) { if (ctx->format().rgba()) qgl_functions()->glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()); else if (!d->cmap.isEmpty()) { // QGLColormap in use? @@ -4420,7 +4432,7 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font) { #ifndef QT_OPENGL_ES Q_D(QGLWidget); - if (!d->glcx->contextHandle()->isES()) { + if (!d->glcx->contextHandle()->isOpenGLES()) { Q_D(QGLWidget); if (str.isEmpty() || !isValid()) return; @@ -4511,7 +4523,7 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con { #ifndef QT_OPENGL_ES Q_D(QGLWidget); - if (!d->glcx->contextHandle()->isES()) { + if (!d->glcx->contextHandle()->isOpenGLES()) { Q_D(QGLWidget); if (str.isEmpty() || !isValid()) return; diff --git a/src/opengl/qgl_qpa.cpp b/src/opengl/qgl_qpa.cpp index fbcc8a5adb..fbabbecdfb 100644 --- a/src/opengl/qgl_qpa.cpp +++ b/src/opengl/qgl_qpa.cpp @@ -326,7 +326,7 @@ QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *) d->context = new QOpenGLContext; #if !defined(QT_OPENGL_ES) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { // On desktop, request latest released version QSurfaceFormat format; #if defined(Q_OS_MAC) diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 050e47c372..cf8b75ce84 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -595,7 +595,7 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, GL_DEPTH_COMPONENT16, size.width(), size.height()); } #else - if (ctx->contextHandle()->isES()) { + if (ctx->contextHandle()->isOpenGLES()) { if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT24, size.width(), size.height()); @@ -617,7 +617,7 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, size.width(), size.height()); } #else - if (ctx->contextHandle()->isES()) { + if (ctx->contextHandle()->isOpenGLES()) { if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, size.width(), size.height()); @@ -647,7 +647,7 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, #ifdef QT_OPENGL_ES GLenum storage = GL_STENCIL_INDEX8; #else - GLenum storage = ctx->contextHandle()->isES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; + GLenum storage = ctx->contextHandle()->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; #endif if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) @@ -849,7 +849,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target) Q_D(QGLFramebufferObject); d->init(this, size, NoAttachment, target, #ifndef QT_OPENGL_ES_2 - QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8 + QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8 #else GL_RGBA #endif @@ -869,7 +869,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target) Q_D(QGLFramebufferObject); d->init(this, QSize(width, height), NoAttachment, target, #ifndef QT_OPENGL_ES_2 - QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8 + QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8 #else GL_RGBA #endif @@ -926,7 +926,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att #ifdef QT_OPENGL_ES_2 internal_format = GL_RGBA; #else - internal_format = QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8; + internal_format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; #endif d->init(this, QSize(width, height), attachment, target, internal_format); } @@ -953,7 +953,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm #ifdef QT_OPENGL_ES_2 internal_format = GL_RGBA; #else - internal_format = QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8; + internal_format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; #endif d->init(this, size, attachment, target, internal_format); } diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h index 0edce5da2f..1aefa0b442 100644 --- a/src/opengl/qglframebufferobject_p.h +++ b/src/opengl/qglframebufferobject_p.h @@ -72,7 +72,7 @@ public: { #ifndef QT_OPENGL_ES_2 QOpenGLContext *ctx = QOpenGLContext::currentContext(); - const bool isES = ctx ? ctx->isES() : QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL; + const bool isES = ctx ? ctx->isOpenGLES() : QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL; internal_format = isES ? GL_RGBA : GL_RGBA8; #else internal_format = GL_RGBA; diff --git a/src/opengl/qglfunctions.cpp b/src/opengl/qglfunctions.cpp index 42b3b47f7f..5ad842bad4 100644 --- a/src/opengl/qglfunctions.cpp +++ b/src/opengl/qglfunctions.cpp @@ -223,7 +223,7 @@ QGLFunctions::QGLFunctions(const QGLContext *context) static int qt_gl_resolve_features() { QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (ctx->isES()) { + if (ctx->isOpenGLES()) { // OpenGL ES 2 int features = QGLFunctions::Multitexture | QGLFunctions::Shaders | diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 8623f44ae1..18dbf4bdbb 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -361,7 +361,7 @@ void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const ctx->functions()->glBindTexture(GL_TEXTURE_2D, texture_id); #ifndef QT_OPENGL_ES - GLenum format = ctx->isES() ? GL_RGBA : GL_RGBA8; + GLenum format = ctx->isOpenGLES() ? GL_RGBA : GL_RGBA8; ctx->functions()->glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, d->req_size.width(), d->req_size.height(), 0); #else ctx->functions()->glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, d->req_size.width(), d->req_size.height(), 0); @@ -488,7 +488,7 @@ GLuint QGLPixelBuffer::bindTexture(const QImage &image, GLenum target) { Q_D(QGLPixelBuffer); #ifndef QT_OPENGL_ES - GLenum format = QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8; + GLenum format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; return d->qctx->bindTexture(image, target, GLint(format)); #else return d->qctx->bindTexture(image, target, GL_RGBA); @@ -507,7 +507,7 @@ GLuint QGLPixelBuffer::bindTexture(const QPixmap &pixmap, GLenum target) { Q_D(QGLPixelBuffer); #ifndef QT_OPENGL_ES - GLenum format = QOpenGLContext::currentContext()->isES() ? GL_RGBA : GL_RGBA8; + GLenum format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; return d->qctx->bindTexture(pixmap, target, GLint(format)); #else return d->qctx->bindTexture(pixmap, target, GL_RGBA); diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index 5314db173e..9cd6ada058 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -248,7 +248,7 @@ bool QGLShaderPrivate::create() shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); #if !defined(QT_OPENGL_ES_2) else if (shaderType == QGLShader::Geometry - && !context->contextHandle()->isES()) + && !context->contextHandle()->isOpenGLES()) shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER_EXT); #endif else @@ -430,14 +430,14 @@ bool QGLShader::compileSourceCode(const char *source) srclen.append(GLint(headerLen)); } #ifdef QGL_DEFINE_QUALIFIERS - if (!QOpenGLContext::currentContext()->isES()) { + if (!QOpenGLContext::currentContext()->isOpenGLES()) { src.append(qualifierDefines); srclen.append(GLint(sizeof(qualifierDefines) - 1)); } #endif #ifdef QGL_REDEFINE_HIGHP if (d->shaderType == Fragment - && QOpenGLContext::currentContext()->isES()) { + && QOpenGLContext::currentContext()->isOpenGLES()) { src.append(redefineHighp); srclen.append(GLint(sizeof(redefineHighp) - 1)); } @@ -568,7 +568,7 @@ public: void initializeGeometryShaderFunctions() { QOpenGLContext *context = QOpenGLContext::currentContext(); - if (!context->isES()) { + if (!context->isOpenGLES()) { glProgramParameteri = (type_glProgramParameteri) context->getProcAddress("glProgramParameteri"); @@ -936,7 +936,7 @@ bool QGLShaderProgram::link() #if !defined(QT_OPENGL_ES_2) // Set up the geometry shader parameters - if (!QOpenGLContext::currentContext()->isES() + if (!QOpenGLContext::currentContext()->isOpenGLES() && d->glfuncs->glProgramParameteri) { foreach (QGLShader *shader, d->shaders) { if (shader->shaderType() & QGLShader::Geometry) { @@ -3075,7 +3075,7 @@ int QGLShaderProgram::maxGeometryOutputVertices() const GLint n = 0; #if !defined(QT_OPENGL_ES_2) Q_D(const QGLShaderProgram); - if (!QOpenGLContext::currentContext()->isES()) + if (!QOpenGLContext::currentContext()->isOpenGLES()) d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &n); #endif return n; diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index e6624fb9ff..5eed47050f 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -66,26 +66,30 @@ QVector q_createConfigAttributesFromFormat(const QSurfaceFormat &format) int stencilSize = format.stencilBufferSize(); int sampleCount = format.samples(); - // We want to make sure 16-bit configs are chosen over 32-bit configs as they will provide - // the best performance. The EGL config selection algorithm is a bit stange in this regard: - // The selection criteria for EGL_BUFFER_SIZE is "AtLeast", so we can't use it to discard - // 32-bit configs completely from the selection. So it then comes to the sorting algorithm. - // The red/green/blue sizes have a sort priority of 3, so they are sorted by first. The sort - // order is special and described as "by larger _total_ number of color bits.". So EGL will - // put 32-bit configs in the list before the 16-bit configs. However, the spec also goes on - // to say "If the requested number of bits in attrib_list for a particular component is 0, - // then the number of bits for that component is not considered". This part of the spec also - // seems to imply that setting the red/green/blue bits to zero means none of the components - // are considered and EGL disregards the entire sorting rule. It then looks to the next - // highest priority rule, which is EGL_BUFFER_SIZE. Despite the selection criteria being - // "AtLeast" for EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are - // put in the list before 32-bit configs. So, to make sure 16-bit is preffered over 32-bit, - // we must set the red/green/blue sizes to zero. This has an unfortunate consequence that - // if the application sets the red/green/blue size to 5/6/5 on the QSurfaceFormat, - // they might still get a 32-bit config, even when there's an RGB565 config available. - QVector configAttributes; + // Map default, unspecified values (-1) to 0. This is important due to sorting rule #3 + // in section 3.4.1 of the spec and allows picking a potentially faster 16-bit config + // over 32-bit ones when there is no explicit request for the color channel sizes: + // + // The red/green/blue sizes have a sort priority of 3, so they are sorted by + // first. (unless a caveat like SLOW or NON_CONFORMANT is present) The sort order is + // Special and described as "by larger _total_ number of color bits.". So EGL will put + // 32-bit configs in the list before the 16-bit configs. However, the spec also goes + // on to say "If the requested number of bits in attrib_list for a particular + // component is 0, then the number of bits for that component is not considered". This + // part of the spec also seems to imply that setting the red/green/blue bits to zero + // means none of the components are considered and EGL disregards the entire sorting + // rule. It then looks to the next highest priority rule, which is + // EGL_BUFFER_SIZE. Despite the selection criteria being "AtLeast" for + // EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are put in the + // list before 32-bit configs. + // + // This also means that explicitly specifying a size like 565 will still result in + // having larger (888) configs first in the returned list. We need to handle this + // ourselves later by manually filtering the list, instead of just blindly taking the + // first config from it. + configAttributes.append(EGL_RED_SIZE); configAttributes.append(redSize > 0 ? redSize : 0); @@ -242,7 +246,7 @@ EGLConfig QEglConfigChooser::chooseConfig() #ifdef EGL_VERSION_1_4 case QSurfaceFormat::DefaultRenderableType: #ifndef QT_NO_OPENGL - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) configureAttributes.append(EGL_OPENGL_BIT); else #endif // QT_NO_OPENGL @@ -293,6 +297,13 @@ EGLConfig QEglConfigChooser::chooseConfig() if (!cfg && matching > 0) cfg = configs.first(); + // Filter the list. Due to the EGL sorting rules configs with higher depth are + // placed first when the minimum color channel sizes have been specified (i.e. the + // QSurfaceFormat contains color sizes > 0). To prevent returning a 888 config + // when the QSurfaceFormat explicitly asked for 565, go through the returned + // configs and look for one that exactly matches the requested sizes. When no + // sizes have been given, take the first, which will be a config with the smaller + // (e.g. 16-bit) depth. for (int i = 0; i < configs.size(); ++i) { if (filterConfig(configs[i])) return configs.at(i); @@ -306,6 +317,8 @@ EGLConfig QEglConfigChooser::chooseConfig() bool QEglConfigChooser::filterConfig(EGLConfig config) const { + // If we are fine with the highest depth (e.g. RGB888 configs) even when something + // smaller (565) was explicitly requested, do nothing. if (m_ignore) return true; @@ -314,6 +327,7 @@ bool QEglConfigChooser::filterConfig(EGLConfig config) const EGLint blue = 0; EGLint alpha = 0; + // Compare only if a size was given. Otherwise just accept. if (m_confAttrRed) eglGetConfigAttrib(display(), config, EGL_RED_SIZE, &red); if (m_confAttrGreen) @@ -366,7 +380,7 @@ QSurfaceFormat q_glFormatFromConfig(EGLDisplay display, const EGLConfig config, format.setRenderableType(QSurfaceFormat::OpenGL); else if (referenceFormat.renderableType() == QSurfaceFormat::DefaultRenderableType #ifndef QT_NO_OPENGL - && QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL + && QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL #endif && (renderableType & EGL_OPENGL_BIT)) format.setRenderableType(QSurfaceFormat::OpenGL); diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index 74a25c1370..9493218024 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -197,7 +197,7 @@ public: Privacy = 0x1 }; - Q_DECLARE_FLAGS(ApFlags, ApFlag); + Q_DECLARE_FLAGS(ApFlags, ApFlag) enum ApSecurityFlag { ApSecurityNone = 0x0, @@ -213,7 +213,7 @@ public: Key8021x = 0x200 }; - Q_DECLARE_FLAGS(ApSecurityFlags, ApSecurityFlag); + Q_DECLARE_FLAGS(ApSecurityFlags, ApSecurityFlag) explicit QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent = 0); ~QNetworkManagerInterfaceAccessPoint(); diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 3324d9ba49..e255a49ac7 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2012 BogDan Vatra ** Contact: http://www.qt-project.org/legal ** @@ -338,7 +339,7 @@ static JNINativeMethod methods[] = { QAndroidInputContext::QAndroidInputContext() - : QPlatformInputContext(), m_blockUpdateSelection(false), m_batchEditNestingLevel(0) + : QPlatformInputContext(), m_composingTextStart(-1), m_blockUpdateSelection(false), m_batchEditNestingLevel(0), m_focusObject(0) { QtAndroid::AttachedJNIEnv env; if (!env.jniEnv) @@ -431,9 +432,24 @@ QAndroidInputContext *QAndroidInputContext::androidInputContext() return m_androidInputContext; } +// cursor position getter that also works with editors that have not been updated to the new API +static inline int getAbsoluteCursorPosition(const QSharedPointer &query) +{ + QVariant absolutePos = query->value(Qt::ImAbsolutePosition); + return absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt(); +} + +// position of the start of the current block +static inline int getBlockPosition(const QSharedPointer &query) +{ + QVariant absolutePos = query->value(Qt::ImAbsolutePosition); + return absolutePos.isValid() ? absolutePos.toInt() - query->value(Qt::ImCursorPosition).toInt() : 0; +} + void QAndroidInputContext::reset() { clear(); + m_batchEditNestingLevel = 0; if (qGuiApp->focusObject()) QtAndroidInput::resetSoftwareKeyboard(); else @@ -449,13 +465,20 @@ void QAndroidInputContext::updateCursorPosition() { QSharedPointer query = focusObjectInputMethodQuery(); if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) { - // make sure it also works with editors that have not been updated to the new API - QVariant absolutePos = query->value(Qt::ImAbsolutePosition); - const int cursorPos = absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt(); + const int cursorPos = getAbsoluteCursorPosition(query); const int composeLength = m_composingText.length(); - const int composeStart = composeLength ? cursorPos : -1; - QtAndroidInput::updateSelection(cursorPos + composeLength, cursorPos + composeLength, //empty selection - composeStart, composeStart + composeLength); // pre-edit text + + //Q_ASSERT(m_composingText.isEmpty() == (m_composingTextStart == -1)); + if (m_composingText.isEmpty() != (m_composingTextStart == -1)) + qWarning() << "Input method out of sync" << m_composingText << m_composingTextStart; + + + // Qt's idea of the cursor position is the start of the preedit area, so we have to maintain our own preedit cursor pos + int realCursorPosition = cursorPos; + if (!m_composingText.isEmpty()) + realCursorPosition = m_composingCursor; + QtAndroidInput::updateSelection(realCursorPosition, realCursorPosition, //empty selection + m_composingTextStart, m_composingTextStart + composeLength); // pre-edit text } } @@ -529,9 +552,22 @@ bool QAndroidInputContext::isComposing() const void QAndroidInputContext::clear() { m_composingText.clear(); + m_composingTextStart = -1; m_extractedText.clear(); } + +void QAndroidInputContext::setFocusObject(QObject *object) +{ + if (object != m_focusObject) { + m_focusObject = object; + if (!m_composingText.isEmpty()) + finishComposingText(); + reset(); + } + QPlatformInputContext::setFocusObject(object); +} + void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodEvent *event) { QCoreApplication::sendEvent(receiver, event); @@ -557,8 +593,18 @@ jboolean QAndroidInputContext::endBatchEdit() jboolean QAndroidInputContext::commitText(const QString &text, jint /*newCursorPosition*/) { + QSharedPointer query = focusObjectInputMethodQuery(); + if (query.isNull()) + return JNI_FALSE; + + + const int cursorPos = getAbsoluteCursorPosition(query); m_composingText = text; - return finishComposingText(); + m_composingTextStart = cursorPos; + m_composingCursor = cursorPos + text.length(); + finishComposingText(); + //### move cursor to newCursorPosition and call updateCursorPosition() + return JNI_TRUE; } jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength) @@ -568,6 +614,7 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right return JNI_TRUE; m_composingText.clear(); + m_composingTextStart = -1; QInputMethodEvent event; event.setCommitString(QString(), -leftLength, leftLength+rightLength); @@ -605,7 +652,9 @@ jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/) return res; } -const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint hintMaxChars, jint /*hintMaxLines*/, jint /*flags*/) + + +const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint /*hintMaxChars*/, jint /*hintMaxLines*/, jint /*flags*/) { // Note to self: "if the GET_EXTRACTED_TEXT_MONITOR flag is set, you should be calling // updateExtractedText(View, int, ExtractedText) whenever you call @@ -616,28 +665,37 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex return m_extractedText; int localPos = query->value(Qt::ImCursorPosition).toInt(); //position before pre-edit text relative to the current block - QVariant absolutePos = query->value(Qt::ImAbsolutePosition); - int blockPos = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0; // position of the start of the current block - QString blockText = query->value(Qt::ImSurroundingText).toString() + m_composingText; + int blockPos = getBlockPosition(query); + QString blockText = query->value(Qt::ImSurroundingText).toString(); int composeLength = m_composingText.length(); + if (composeLength > 0) { + //Qt doesn't give us the preedit text, so we have to insert it at the correct position + int localComposePos = m_composingTextStart - blockPos; + blockText = blockText.left(localComposePos) + m_composingText + blockText.mid(localComposePos); + } + int cpos = localPos + composeLength; //actual cursor pos relative to the current block int localOffset = 0; // start of extracted text relative to the current block - if (hintMaxChars) { - if (cpos > hintMaxChars) - localOffset = cpos - hintMaxChars; - m_extractedText.text = blockText.mid(localOffset, hintMaxChars); - } - m_extractedText.startOffset = blockPos + localOffset; // "The offset in the overall text at which the extracted text starts." + // It is documented that we should try to return hintMaxChars + // characters, but that's not what the standard Android controls do, and + // there are input methods out there that (surprise) seem to depend on + // what happens in reality rather than what's documented. + + m_extractedText.text = blockText; + m_extractedText.startOffset = blockPos + localOffset; const QString &selection = query->value(Qt::ImCurrentSelection).toString(); const int selLen = selection.length(); if (selLen) { m_extractedText.selectionStart = query->value(Qt::ImAnchorPosition).toInt() - localOffset; m_extractedText.selectionEnd = m_extractedText.selectionStart + selLen; - } else { + } else if (composeLength > 0) { + m_extractedText.selectionStart = m_composingCursor - m_extractedText.startOffset; + m_extractedText.selectionEnd = m_composingCursor - m_extractedText.startOffset; + } else { m_extractedText.selectionStart = cpos - localOffset; m_extractedText.selectionEnd = cpos - localOffset; } @@ -656,6 +714,7 @@ QString QAndroidInputContext::getSelectedText(jint /*flags*/) QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/) { + //### the preedit text could theoretically be after the cursor QVariant textAfter = queryFocusObjectThreadSafe(Qt::ImTextAfterCursor, QVariant(length)); if (textAfter.isValid()) { return textAfter.toString().left(length); @@ -678,7 +737,7 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/) { QVariant textBefore = queryFocusObjectThreadSafe(Qt::ImTextBeforeCursor, QVariant(length)); if (textBefore.isValid()) { - return textBefore.toString().left(length) + m_composingText; + return textBefore.toString().right(length) + m_composingText; } //compatibility code for old controls that do not implement the new API @@ -691,15 +750,34 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/) if (!text.length()) return text; - const int wordLeftPos = cursorPos - length; - return text.mid(wordLeftPos > 0 ? wordLeftPos : 0, cursorPos) + m_composingText; + //### the preedit text does not need to be immediately before the cursor + if (cursorPos <= length) + return text.left(cursorPos) + m_composingText; + else + return text.mid(cursorPos - length, length) + m_composingText; } +/* + Android docs say that this function should remove the current preedit text + if any, and replace it with the given text. Any selected text should be + removed. The cursor is then moved to newCursorPosition. If > 0, this is + relative to the end of the text - 1; if <= 0, this is relative to the start + of the text. + */ + jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition) { + QSharedPointer query = focusObjectInputMethodQuery(); + if (query.isNull()) + return JNI_FALSE; + + const int cursorPos = getAbsoluteCursorPosition(query); if (newCursorPosition > 0) newCursorPosition += text.length() - 1; + m_composingText = text; + m_composingTextStart = text.isEmpty() ? -1 : cursorPos; + m_composingCursor = cursorPos + newCursorPosition; QList attributes; attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, newCursorPosition, @@ -714,23 +792,26 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur QInputMethodEvent event(m_composingText, attributes); sendInputMethodEvent(&event); - QSharedPointer query = focusObjectInputMethodQuery(); - if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) { - QVariant absolutePos = query->value(Qt::ImAbsolutePosition); - const int cursorPos = absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt(); - const int preeditLength = text.length(); - QtAndroidInput::updateSelection(cursorPos+preeditLength, cursorPos+preeditLength, -1, -1); - } + updateCursorPosition(); return JNI_TRUE; } // Android docs say: // * start may be after end, same meaning as if swapped -// * this function must not trigger updateSelection +// * this function should not trigger updateSelection // * if start == end then we should stop composing jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) { + // Qt will not include the current preedit text in the query results, and interprets all + // parameters relative to the text excluding the preedit. The simplest solution is therefore to + // tell Qt that we commit the text before we set the new region. This may cause a little flicker, but is + // much more robust than trying to keep the two different world views in sync + + bool wasComposing = !m_composingText.isEmpty(); + if (wasComposing) + finishComposingText(); + QSharedPointer query = focusObjectInputMethodQuery(); if (query.isNull()) return JNI_FALSE; @@ -745,19 +826,23 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) Therefore, the length of the region is end - start */ + int length = end - start; int localPos = query->value(Qt::ImCursorPosition).toInt(); - QVariant absolutePos = query->value(Qt::ImAbsolutePosition); - int blockPosition = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0; + int blockPosition = getBlockPosition(query); int localStart = start - blockPosition; // Qt uses position inside block + int currentCursor = wasComposing ? m_composingCursor : blockPosition + localPos; bool updateSelectionWasBlocked = m_blockUpdateSelection; m_blockUpdateSelection = true; QString text = query->value(Qt::ImSurroundingText).toString(); - m_composingText = text.mid(localStart, length); - //in the Qt text controls, the cursor position is the start of the preedit + m_composingText = text.mid(localStart, length); + m_composingTextStart = start; + m_composingCursor = currentCursor; + + //in the Qt text controls, the preedit is defined relative to the cursor position int relativeStart = localStart - localPos; QList attributes; @@ -769,13 +854,22 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) QVariant(underlined))); // Keep the cursor position unchanged (don't move to end of preedit) - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, localPos - localStart, length, QVariant())); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, currentCursor - start, 1, QVariant())); QInputMethodEvent event(m_composingText, attributes); event.setCommitString(QString(), relativeStart, length); sendInputMethodEvent(&event); m_blockUpdateSelection = updateSelectionWasBlocked; + +#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL + QSharedPointer query2 = focusObjectInputMethodQuery(); + if (!query2.isNull()) { + qDebug() << "Setting. Prev local cpos:" << localPos << "block pos:" <value(Qt::ImCursorPosition).toInt(); - QVariant absolutePos = query->value(Qt::ImAbsolutePosition); - int blockPosition = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0; + int blockPosition = getBlockPosition(query); + int localCursorPos = start - blockPosition; QList attributes; - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, - start - blockPosition, - end - start, - QVariant())); + if (!m_composingText.isEmpty() && start == end) { + // not actually changing the selection; just moving the + // preedit cursor + int localOldPos = query->value(Qt::ImCursorPosition).toInt(); + int pos = localCursorPos - localOldPos; + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1, QVariant())); - QInputMethodEvent event(QString(), attributes); + //but we have to tell Qt about the compose text all over again + + // Show compose text underlined + QTextCharFormat underlined; + underlined.setFontUnderline(true); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, m_composingText.length(), + QVariant(underlined))); + m_composingCursor = start; + + } else { + // actually changing the selection + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, + localCursorPos, + end - start, + QVariant())); + } + QInputMethodEvent event(m_composingText, attributes); sendInputMethodEvent(&event); + updateCursorPosition(); return JNI_TRUE; } diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h index f7b29a855f..a467e4849e 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.h +++ b/src/plugins/platforms/android/qandroidinputcontext.h @@ -95,6 +95,7 @@ public: bool isComposing() const; void clear(); + void setFocusObject(QObject *object); //---------------// jboolean beginBatchEdit(); @@ -133,9 +134,12 @@ private slots: private: ExtractedText m_extractedText; QString m_composingText; + int m_composingTextStart; + int m_composingCursor; QMetaObject::Connection m_updateCursorPosConnection; bool m_blockUpdateSelection; int m_batchEditNestingLevel; + QObject *m_focusObject; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index a60f4adc28..1f9c0e051d 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -2,6 +2,7 @@ TARGET = qcocoa PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) OBJECTIVE_SOURCES += main.mm \ diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 1df4230385..dd3b9f53db 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -168,6 +168,14 @@ // TODO: multi-selection: NSAccessibilitySelectedTextRangesAttribute, } + if (iface->valueInterface()) { + [attributes addObjectsFromArray: [[NSArray alloc] initWithObjects: + NSAccessibilityMinValueAttribute, + NSAccessibilityMaxValueAttribute, + nil + ]]; + } + return [attributes autorelease]; } @@ -191,6 +199,19 @@ return [QCocoaAccessibleElement elementWithId: parentId]; } + +- (id) minValueAttribute:(QAccessibleInterface*)iface { + if (QAccessibleValueInterface *val = iface->valueInterface()) + return [NSNumber numberWithDouble: val->minimumValue().toDouble()]; + return nil; +} + +- (id) maxValueAttribute:(QAccessibleInterface*)iface { + if (QAccessibleValueInterface *val = iface->valueInterface()) + return [NSNumber numberWithDouble: val->maximumValue().toDouble()]; + return nil; +} + - (id)accessibilityAttributeValue:(NSString *)attribute { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (!iface) { @@ -272,6 +293,10 @@ return [NSNumber numberWithInt: textBeforeCursor.count(QLatin1Char('\n'))]; } return nil; + } else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) { + return [self minValueAttribute:iface]; + } else if ([attribute isEqualToString:NSAccessibilityMaxValueAttribute]) { + return [self maxValueAttribute:iface]; } return nil; @@ -332,7 +357,7 @@ startOffset = text.indexOf(QLatin1Char('\n'), startOffset) + 1; if (startOffset < 0) // invalid line number, return the first line startOffset = 0; - int endOffset = text.indexOf(QLatin1Char('\n'), startOffset + 1); + int endOffset = text.indexOf(QLatin1Char('\n'), startOffset); if (endOffset == -1) endOffset = text.length(); return [NSValue valueWithRange:NSMakeRange(quint32(startOffset), quint32(endOffset - startOffset))]; @@ -359,6 +384,12 @@ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { return iface->state().focusable ? YES : NO; + } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + if (iface->textInterface() && iface->state().editable) + return YES; + if (iface->valueInterface()) + return YES; + return NO; } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { return iface->textInterface() ? YES : NO; } @@ -372,6 +403,14 @@ if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) { if (QAccessibleActionInterface *action = iface->actionInterface()) action->doAction(QAccessibleActionInterface::setFocusAction()); + } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) { + if (iface->textInterface()) { + QString text = QString::fromNSString((NSString *)value); + iface->setText(QAccessible::Value, text); + } else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) { + double val = [value doubleValue]; + valueIface->setCurrentValue(val); + } } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) { if (QAccessibleTextInterface *text = iface->textInterface()) { NSRange range = [value rangeValue]; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 0274ed8201..de6c6585e9 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -134,6 +134,8 @@ public: void interrupt(); void flush(); + bool event(QEvent *); + friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher); }; @@ -163,7 +165,6 @@ public: // The following variables help organizing modal sessions: QStack cocoaModalSessionStack; bool currentExecIsNSAppRun; - bool modalSessionOnNSAppRun; bool nsAppRunCalledByQt; bool cleanupModalSessionsNeeded; uint processEventsCalled; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 495a54cac4..e0ce9f9648 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -734,13 +734,25 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window) updateChildrenWorksWhenModal(); currentModalSessionCached = 0; if (currentExecIsNSAppRun) { - modalSessionOnNSAppRun = true; - q->wakeUp(); + QEvent *e = new QEvent(QEvent::User); + qApp->postEvent(q, e, Qt::HighEventPriority); } else { q->interrupt(); } } +bool QCocoaEventDispatcher::event(QEvent *e) +{ + Q_D(QCocoaEventDispatcher); + + if (e->type() == QEvent::User) { + d->q_func()->processEvents(QEventLoop::DialogExec | QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents); + return true; + } + + return QObject::event(e); +} + void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window) { Q_Q(QCocoaEventDispatcher); @@ -777,7 +789,6 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate() runLoopTimerRef(0), blockSendPostedEvents(false), currentExecIsNSAppRun(false), - modalSessionOnNSAppRun(false), nsAppRunCalledByQt(false), cleanupModalSessionsNeeded(false), processEventsCalled(0), @@ -908,14 +919,6 @@ void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info) // processEvents() was called "manually," ignore this source for now d->maybeCancelWaitForMoreEvents(); return; - } else if (d->modalSessionOnNSAppRun) { - // We're about to spawn the 1st modal session on top of the main runloop. - // Instead of calling processPostedEvents(), which would need us stop - // NSApp, we just re-enter processEvents(). This is equivalent to calling - // QDialog::exec() except that it's done in a non-blocking way. - d->modalSessionOnNSAppRun = false; - d->q_func()->processEvents(QEventLoop::DialogExec | QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents); - return; } d->processPostedEvents(); d->maybeCancelWaitForMoreEvents(); diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 59fda96dff..3ee1dab84d 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -68,6 +68,7 @@ public: void setEnabled(bool enabled); void setVisible(bool visible); void showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item); + void dismiss(); void syncSeparatorsCollapsible(bool enable); diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 6acc062eb9..44bc3b8f69 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -490,6 +490,11 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatf [(QNSView *)view resetMouseButtons]; } +void QCocoaMenu::dismiss() +{ + [m_nativeMenu cancelTracking]; +} + QPlatformMenuItem *QCocoaMenu::menuItemAt(int position) const { if (0 <= position && position < m_menuItems.count()) diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index ffc0fabdce..aceb9b619b 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -124,6 +124,8 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor m_menus.insert(beforeMenu ? m_menus.indexOf(beforeMenu) : m_menus.size(), menu); if (!menu->menuBar()) insertNativeMenu(menu, beforeMenu); + if (m_window && m_window->window()->isActive()) + updateMenuBarImmediately(); } void QCocoaMenuBar::removeNativeMenu(QCocoaMenu *menu) diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index 61706c19bc..1efc9f9bfd 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -57,6 +57,7 @@ QT_FORWARD_DECLARE_OBJC_CLASS(NSMenuItem); QT_FORWARD_DECLARE_OBJC_CLASS(NSMenu); QT_FORWARD_DECLARE_OBJC_CLASS(NSObject); +QT_FORWARD_DECLARE_OBJC_CLASS(NSView); QT_BEGIN_NAMESPACE @@ -86,6 +87,8 @@ public: void setChecked(bool isChecked); void setEnabled(bool isEnabled); + void setNativeContents(WId item); + inline QString text() const { return m_text; } inline NSMenuItem * nsItem() { return m_native; } NSMenuItem *sync(); @@ -105,6 +108,7 @@ private: QKeySequence mergeAccel(); NSMenuItem *m_native; + NSView *m_itemView; QString m_text; bool m_textSynced; QIcon m_icon; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 58fe07bc62..99d26034bf 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -91,6 +91,7 @@ NSUInteger keySequenceModifierMask(const QKeySequence &accel) QCocoaMenuItem::QCocoaMenuItem() : m_native(NULL), + m_itemView(nil), m_textSynced(false), m_menu(NULL), m_isVisible(true), @@ -110,6 +111,8 @@ QCocoaMenuItem::~QCocoaMenuItem() } else { [m_native release]; } + + [m_itemView release]; } void QCocoaMenuItem::setText(const QString &text) @@ -178,6 +181,17 @@ void QCocoaMenuItem::setEnabled(bool enabled) m_enabled = enabled; } +void QCocoaMenuItem::setNativeContents(WId item) +{ + NSView *itemView = (NSView *)item; + [m_itemView release]; + m_itemView = [itemView retain]; + [m_itemView setAutoresizesSubviews:YES]; + [m_itemView setAutoresizingMask:NSViewWidthSizable]; + [m_itemView setHidden:NO]; + [m_itemView setNeedsDisplay:YES]; +} + NSMenuItem *QCocoaMenuItem::sync() { if (m_isSeparator != [m_native isSeparatorItem]) { @@ -281,6 +295,7 @@ NSMenuItem *QCocoaMenuItem::sync() [m_native setHidden: !m_isVisible]; [m_native setEnabled: m_enabled]; + [m_native setView:m_itemView]; QString text = mergeText(); QKeySequence accel = mergeAccel(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 5def64ee0a..60152b56b2 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1375,7 +1375,8 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow() qPlatformWindow:this]; if ((type & Qt::Popup) == Qt::Popup) [window setHasShadow:YES]; - [window setHidesOnDeactivate: NO]; + + [window setHidesOnDeactivate:(type & Qt::Tool) == Qt::Tool]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 0b9683a3ef..24a9f6fff0 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -42,6 +42,7 @@ #include #include +#include #include "qnsview.h" #include "qcocoawindow.h" @@ -65,6 +66,9 @@ static QTouchDevice *touchDevice = 0; +// ### HACK Remove once 10.8 is unsupported +static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; + @interface NSEvent (Qt_Compile_Leopard_DeviceDelta) - (CGFloat)deviceDeltaX; - (CGFloat)deviceDeltaY; @@ -73,6 +77,13 @@ static QTouchDevice *touchDevice = 0; @implementation QNSView ++ (void)initialize +{ + NSString **notificationNameVar = (NSString **)dlsym(RTLD_NEXT, "NSWindowDidChangeOcclusionStateNotification"); + if (notificationNameVar) + _q_NSWindowDidChangeOcclusionStateNotification = *notificationNameVar; +} + - (id) init { self = [super initWithFrame : NSMakeRect(0,0, 300,300)]; @@ -192,6 +203,19 @@ static QTouchDevice *touchDevice = 0; } } +- (void)viewDidMoveToWindow +{ + if (self.window) { + // This is the case of QWidgetAction's generated QWidget inserted in an NSMenu. + // 10.9 and newer get the NSWindowDidChangeOcclusionStateNotification + if (!_q_NSWindowDidChangeOcclusionStateNotification + && [self.window.className isEqualToString:@"NSCarbonMenuWindow"]) + m_platformWindow->exposeWindow(); + } else { + m_platformWindow->obscureWindow(); + } +} + - (void)viewWillMoveToWindow:(NSWindow *)newWindow { // ### Merge "normal" window code path with this one for 5.1. @@ -325,6 +349,23 @@ static QTouchDevice *touchDevice = 0; m_platformWindow->obscureWindow(); } else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) { m_platformWindow->exposeWindow(); + } else if (_q_NSWindowDidChangeOcclusionStateNotification + && [notificationName isEqualToString:_q_NSWindowDidChangeOcclusionStateNotification]) { +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 +// ### HACK Remove the enum declaration, the warning disabling and the cast further down once 10.8 is unsupported +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-method-access" + enum { NSWindowOcclusionStateVisible = 1UL << 1 }; +#endif + // Older versions managed in -[QNSView viewDidMoveToWindow]. + // Support QWidgetAction in NSMenu. Mavericks only sends this notification. + // Ideally we should support this in Qt as well, in order to disable animations + // when the window is occluded. + if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) + m_platformWindow->exposeWindow(); +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 +#pragma clang diagnostic pop +#endif } else if (notificationName == NSWindowDidChangeScreenNotification) { if (m_window) { NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen]; @@ -637,10 +678,14 @@ static QTouchDevice *touchDevice = 0; return [super mouseDown:theEvent]; m_sendUpAsRightButton = false; if (m_platformWindow->m_activePopupWindow) { + Qt::WindowType type = m_platformWindow->m_activePopupWindow->type(); QWindowSystemInterface::handleCloseEvent(m_platformWindow->m_activePopupWindow); QWindowSystemInterface::flushWindowSystemEvents(); m_platformWindow->m_activePopupWindow = 0; - return; + // Consume the mouse event when closing the popup, except for tool tips + // were it's expected that the event is processed normally. + if (type != Qt::ToolTip) + return; } if ([self hasMarkedText]) { NSInputManager* inputManager = [NSInputManager currentInputManager]; diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro index 4f986b57d7..439d31fb56 100644 --- a/src/plugins/platforms/direct2d/direct2d.pro +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -2,6 +2,7 @@ TARGET = qdirect2d PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWindowsDirect2DIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT *= core-private diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp index 079ad6f127..e4ce81bd24 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp @@ -75,6 +75,16 @@ QWindowsDirect2DBackingStore::~QWindowsDirect2DBackingStore() { } +void QWindowsDirect2DBackingStore::beginPaint(const QRegion &) +{ + platformPixmap(m_pixmap.data())->bitmap()->deviceContext()->begin(); +} + +void QWindowsDirect2DBackingStore::endPaint() +{ + platformPixmap(m_pixmap.data())->bitmap()->deviceContext()->end(); +} + QPaintDevice *QWindowsDirect2DBackingStore::paintDevice() { return m_pixmap.data(); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h index 9776d234e8..fc6802aaa2 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h @@ -58,6 +58,9 @@ public: QWindowsDirect2DBackingStore(QWindow *window); ~QWindowsDirect2DBackingStore(); + void beginPaint(const QRegion &); + void endPaint(); + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h index 98248515e6..3be05ee1e0 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h @@ -84,8 +84,6 @@ Q_DECL_CONSTEXPR inline D2D1::ColorF to_d2d_color_f(const QColor &c) Q_DECL_CONSTEXPR inline D2D1_MATRIX_3X2_F to_d2d_matrix_3x2_f(const QTransform &transform) { - Q_ASSERT(transform.isAffine()); - return D2D1::Matrix3x2F(transform.m11(), transform.m12(), transform.m21(), transform.m22(), transform.m31(), transform.m32()); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index d8f34fc3ed..58c30b6eeb 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -52,6 +52,7 @@ #include "qwindowsfontdatabase.h" #include "qwindowsintegration.h" +#include #include #include #include @@ -71,8 +72,15 @@ QT_BEGIN_NAMESPACE // http://msdn.microsoft.com/en-us/library/windows/desktop/dd370979(v=vs.85).aspx enum { D2DDebugDrawInitialStateTag = -1, - D2DDebugDrawImageTag = 1, - D2DDebugFillTag, + D2DDebugFillTag = 1, + D2DDebugFillRectTag, + D2DDebugDrawRectsTag, + D2DDebugDrawRectFsTag, + D2DDebugDrawLinesTag, + D2DDebugDrawLineFsTag, + D2DDebugDrawEllipseTag, + D2DDebugDrawEllipseFTag, + D2DDebugDrawImageTag, D2DDebugDrawPixmapTag, D2DDebugDrawStaticTextItemTag, D2DDebugDrawTextItemTag @@ -80,9 +88,19 @@ enum { //Clipping flags enum { - UserClip = 0x1, - SimpleSystemClip = 0x2 + SimpleSystemClip = 0x1 }; + +enum ClipType { + AxisAlignedClip, + LayerClip +}; + +// Since d2d is a float-based system we need to be able to snap our drawing to whole pixels. +// Applying the magical aliasing offset to coordinates will do so, just make sure that +// aliased painting is turned on on the d2d device context. +static const qreal MAGICAL_ALIASING_OFFSET = 0.5; + #define D2D_TAG(tag) d->dc()->SetTags(tag, tag) Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); @@ -92,51 +110,127 @@ static inline ID2D1Factory1 *factory() return QWindowsDirect2DContext::instance()->d2dFactory(); } -// XXX reduce code duplication between painterPathToPathGeometry and -// vectorPathToID2D1PathGeometry, the two are quite similar - -static ComPtr painterPathToPathGeometry(const QPainterPath &path) +class Direct2DPathGeometryWriter { - ComPtr geometry; - ComPtr sink; +public: + Direct2DPathGeometryWriter() + : m_inFigure(false) + , m_roundCoordinates(false) + { - HRESULT hr = factory()->CreatePathGeometry(&geometry); - if (FAILED(hr)) { - qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr); + } + + bool begin() + { + HRESULT hr = factory()->CreatePathGeometry(&m_geometry); + if (FAILED(hr)) { + qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr); + return false; + } + + hr = m_geometry->Open(&m_sink); + if (FAILED(hr)) { + qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr); + return false; + } + + return true; + } + + void setWindingFillEnabled(bool enable) + { + if (enable) + m_sink->SetFillMode(D2D1_FILL_MODE_WINDING); + else + m_sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); + } + + void setAliasingEnabled(bool enable) + { + m_roundCoordinates = enable; + } + + bool isInFigure() const + { + return m_inFigure; + } + + void moveTo(const QPointF &point) + { + if (m_inFigure) + m_sink->EndFigure(D2D1_FIGURE_END_OPEN); + + m_sink->BeginFigure(adjusted(point), D2D1_FIGURE_BEGIN_FILLED); + m_inFigure = true; + } + + void lineTo(const QPointF &point) + { + m_sink->AddLine(adjusted(point)); + } + + void curveTo(const QPointF &p1, const QPointF &p2, const QPointF &p3) + { + D2D1_BEZIER_SEGMENT segment = { + adjusted(p1), + adjusted(p2), + adjusted(p3) + }; + + m_sink->AddBezier(segment); + } + + void close() + { + if (m_inFigure) + m_sink->EndFigure(D2D1_FIGURE_END_OPEN); + + m_sink->Close(); + } + + ComPtr geometry() const + { + return m_geometry; + } + +private: + D2D1_POINT_2F adjusted(const QPointF &point) + { + static const QPointF adjustment(MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET); + + if (m_roundCoordinates) + return to_d2d_point_2f(point + adjustment); + else + return to_d2d_point_2f(point); + } + + ComPtr m_geometry; + ComPtr m_sink; + + bool m_inFigure; + bool m_roundCoordinates; +}; + +static ComPtr painterPathToID2D1PathGeometry(const QPainterPath &path, bool alias) +{ + Direct2DPathGeometryWriter writer; + if (!writer.begin()) return NULL; - } - hr = geometry->Open(&sink); - if (FAILED(hr)) { - qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr); - return NULL; - } - - switch (path.fillRule()) { - case Qt::WindingFill: - sink->SetFillMode(D2D1_FILL_MODE_WINDING); - break; - case Qt::OddEvenFill: - sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); - break; - } - - bool inFigure = false; + writer.setWindingFillEnabled(path.fillRule() == Qt::WindingFill); + writer.setAliasingEnabled(alias); for (int i = 0; i < path.elementCount(); i++) { const QPainterPath::Element element = path.elementAt(i); switch (element.type) { case QPainterPath::MoveToElement: - if (inFigure) - sink->EndFigure(D2D1_FIGURE_END_OPEN); - - sink->BeginFigure(to_d2d_point_2f(element), D2D1_FIGURE_BEGIN_FILLED); - inFigure = true; + writer.moveTo(element); break; case QPainterPath::LineToElement: - sink->AddLine(to_d2d_point_2f(element)); + writer.lineTo(element); break; case QPainterPath::CurveToElement: @@ -149,13 +243,7 @@ static ComPtr painterPathToPathGeometry(const QPainterPath & Q_ASSERT(data1.type == QPainterPath::CurveToDataElement); Q_ASSERT(data2.type == QPainterPath::CurveToDataElement); - D2D1_BEZIER_SEGMENT segment; - - segment.point1 = to_d2d_point_2f(element); - segment.point2 = to_d2d_point_2f(data1); - segment.point3 = to_d2d_point_2f(data2); - - sink->AddBezier(segment); + writer.curveTo(element, data1, data2); } break; @@ -165,55 +253,22 @@ static ComPtr painterPathToPathGeometry(const QPainterPath & } } - if (inFigure) - sink->EndFigure(D2D1_FIGURE_END_OPEN); - - sink->Close(); - - return geometry; + writer.close(); + return writer.geometry(); } static ComPtr vectorPathToID2D1PathGeometry(const QVectorPath &path, bool alias) { - ComPtr pathGeometry; - HRESULT hr = factory()->CreatePathGeometry(pathGeometry.GetAddressOf()); - if (FAILED(hr)) { - qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr); + Direct2DPathGeometryWriter writer; + if (!writer.begin()) return NULL; - } - if (path.isEmpty()) - return pathGeometry; - - ComPtr sink; - hr = pathGeometry->Open(sink.GetAddressOf()); - if (FAILED(hr)) { - qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr); - return NULL; - } - - sink->SetFillMode(path.hasWindingFill() ? D2D1_FILL_MODE_WINDING - : D2D1_FILL_MODE_ALTERNATE); - - bool inFigure = false; + writer.setWindingFillEnabled(path.hasWindingFill()); + writer.setAliasingEnabled(alias); const QPainterPath::ElementType *types = path.elements(); const int count = path.elementCount(); - const qreal *points = 0; - - QScopedArrayPointer rounded_points; - - if (alias) { - // Aliased painting, round to whole numbers - rounded_points.reset(new qreal[count * 2]); - points = rounded_points.data(); - - for (int i = 0; i < (count * 2); i++) - rounded_points[i] = qRound(path.points()[i]); - } else { - // Antialiased painting, keep original numbers - points = path.points(); - } + const qreal *points = path.points(); Q_ASSERT(points); @@ -226,15 +281,11 @@ static ComPtr vectorPathToID2D1PathGeometry(const QVectorPat switch (types[i]) { case QPainterPath::MoveToElement: - if (inFigure) - sink->EndFigure(D2D1_FIGURE_END_OPEN); - - sink->BeginFigure(D2D1::Point2F(x, y), D2D1_FIGURE_BEGIN_FILLED); - inFigure = true; + writer.moveTo(QPointF(x, y)); break; case QPainterPath::LineToElement: - sink->AddLine(D2D1::Point2F(x, y)); + writer.lineTo(QPointF(x, y)); break; case QPainterPath::CurveToElement: @@ -251,13 +302,7 @@ static ComPtr vectorPathToID2D1PathGeometry(const QVectorPat const qreal x3 = points[i * 2]; const qreal y3 = points[i * 2 + 1]; - D2D1_BEZIER_SEGMENT segment = { - D2D1::Point2F(x, y), - D2D1::Point2F(x2, y2), - D2D1::Point2F(x3, y3) - }; - - sink->AddBezier(segment); + writer.curveTo(QPointF(x, y), QPointF(x2, y2), QPointF(x3, y3)); } break; @@ -267,23 +312,17 @@ static ComPtr vectorPathToID2D1PathGeometry(const QVectorPat } } } else { - sink->BeginFigure(D2D1::Point2F(points[0], points[1]), D2D1_FIGURE_BEGIN_FILLED); - inFigure = true; - + writer.moveTo(QPointF(points[0], points[1])); for (int i = 1; i < count; i++) - sink->AddLine(D2D1::Point2F(points[i * 2], points[i * 2 + 1])); + writer.lineTo(QPointF(points[i * 2], points[i * 2 + 1])); } - if (inFigure) { + if (writer.isInFigure()) if (path.hasImplicitClose()) - sink->AddLine(D2D1::Point2F(points[0], points[1])); + writer.lineTo(QPointF(points[0], points[1])); - sink->EndFigure(D2D1_FIGURE_END_OPEN); - } - - sink->Close(); - - return pathGeometry; + writer.close(); + return writer.geometry(); } class QWindowsDirect2DPaintEnginePrivate : public QPaintEngineExPrivate @@ -302,8 +341,8 @@ public: QWindowsDirect2DBitmap *bitmap; - QPainterPath clipPath; unsigned int clipFlags; + QStack pushedClips; QPointF currentBrushOrigin; @@ -354,81 +393,97 @@ public: : D2D1_ANTIALIAS_MODE_ALIASED; } - void updateTransform() + void updateTransform(const QTransform &transform) { - Q_Q(const QWindowsDirect2DPaintEngine); - // Note the loss of info going from 3x3 to 3x2 matrix here - dc()->SetTransform(to_d2d_matrix_3x2_f(q->state()->transform())); + dc()->SetTransform(to_d2d_matrix_3x2_f(transform)); } - void updateOpacity() + void updateOpacity(qreal opacity) { - Q_Q(const QWindowsDirect2DPaintEngine); - qreal opacity = q->state()->opacity; if (brush.brush) brush.brush->SetOpacity(opacity); if (pen.brush) pen.brush->SetOpacity(opacity); } - void pushClip() + void pushClip(const QVectorPath &path) { - popClip(); + Q_Q(QWindowsDirect2DPaintEngine); - ComPtr geometry = painterPathToPathGeometry(clipPath); - if (!geometry) - return; + if (path.isEmpty()) { + D2D_RECT_F rect = {0, 0, 0, 0}; + dc()->PushAxisAlignedClip(rect, antialiasMode()); + pushedClips.push(AxisAlignedClip); + } else if (path.isRect() && (q->state()->matrix.type() <= QTransform::TxScale)) { + const qreal * const points = path.points(); + D2D_RECT_F rect = { + points[0], // left + points[1], // top + points[2], // right, + points[5] // bottom + }; - dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), - geometry.Get(), - antialiasMode(), - D2D1::IdentityMatrix(), - 1.0, - NULL, - D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND), - NULL); - clipFlags |= UserClip; - } + dc()->PushAxisAlignedClip(rect, antialiasMode()); + pushedClips.push(AxisAlignedClip); + } else { + ComPtr geometry = vectorPathToID2D1PathGeometry(path, antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED); + if (!geometry) { + qWarning("%s: Could not convert vector path to painter path!", __FUNCTION__); + return; + } - void popClip() - { - if (clipFlags & UserClip) { - dc()->PopLayer(); - clipFlags &= ~UserClip; + dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), + geometry.Get(), + antialiasMode(), + D2D1::IdentityMatrix(), + 1.0, + NULL, + D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND), + NULL); + pushedClips.push(LayerClip); } } - void updateClipEnabled() + void clearClips() { - Q_Q(const QWindowsDirect2DPaintEngine); - if (!q->state()->clipEnabled) - popClip(); - else if (!(clipFlags & UserClip)) - pushClip(); + while (!pushedClips.isEmpty()) { + switch (pushedClips.pop()) { + case AxisAlignedClip: + dc()->PopAxisAlignedClip(); + break; + case LayerClip: + dc()->PopLayer(); + break; + } + } } - void updateClipPath(const QPainterPath &path, Qt::ClipOperation operation) + void updateClipEnabled(bool enabled) + { + if (!enabled) + clearClips(); + else if (pushedClips.isEmpty()) + replayClipOperations(); + } + + void clip(const QVectorPath &path, Qt::ClipOperation operation) { switch (operation) { case Qt::NoClip: - popClip(); + clearClips(); break; case Qt::ReplaceClip: - clipPath = path; - pushClip(); + clearClips(); + pushClip(path); break; case Qt::IntersectClip: - clipPath &= path; - pushClip(); + pushClip(path); break; } } - void updateCompositionMode() + void updateCompositionMode(QPainter::CompositionMode mode) { - Q_Q(const QWindowsDirect2DPaintEngine); - QPainter::CompositionMode mode = q->state()->compositionMode(); - switch (mode) { case QPainter::CompositionMode_Source: dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY); @@ -447,7 +502,7 @@ public: { Q_Q(const QWindowsDirect2DPaintEngine); - if (qbrush_fast_equals(brush.qbrush, newBrush)) + if (qbrush_fast_equals(brush.qbrush, newBrush) && (brush.brush || brush.emulate)) return; brush.brush = to_d2d_brush(newBrush, &brush.emulate); @@ -459,12 +514,10 @@ public: } } - void updateBrushOrigin() + void updateBrushOrigin(const QPointF &brushOrigin) { - Q_Q(const QWindowsDirect2DPaintEngine); - negateCurrentBrushOrigin(); - applyBrushOrigin(q->state()->brushOrigin); + applyBrushOrigin(brushOrigin); } void negateCurrentBrushOrigin() @@ -492,12 +545,10 @@ public: currentBrushOrigin = origin; } - void updatePen() + void updatePen(const QPen &newPen) { Q_Q(const QWindowsDirect2DPaintEngine); - const QPen &newPen = q->state()->pen; - - if (qpen_fast_equals(newPen, pen.qpen)) + if (qpen_fast_equals(newPen, pen.qpen) && (pen.brush || pen.emulate)) return; pen.reset(); @@ -658,7 +709,91 @@ public: break; case Qt::LinearGradientPattern: + if (newBrush.gradient()->spread() != QGradient::PadSpread) { + *needsEmulation = true; + } else { + ComPtr linear; + const QLinearGradient *qlinear = static_cast(newBrush.gradient()); + + D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES linearGradientBrushProperties; + ComPtr gradientStopCollection; + + const QGradientStops &qstops = qlinear->stops(); + QVector stops(qstops.count()); + + linearGradientBrushProperties.startPoint = to_d2d_point_2f(qlinear->start()); + linearGradientBrushProperties.endPoint = to_d2d_point_2f(qlinear->finalStop()); + + for (int i = 0; i < stops.size(); i++) { + stops[i].position = qstops[i].first; + stops[i].color = to_d2d_color_f(qstops[i].second); + } + + hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection); + if (FAILED(hr)) { + qWarning("%s: Could not create gradient stop collection for linear gradient: %#x", __FUNCTION__, hr); + break; + } + + hr = dc()->CreateLinearGradientBrush(linearGradientBrushProperties, gradientStopCollection.Get(), + &linear); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D linear gradient brush: %#x", __FUNCTION__, hr); + break; + } + + hr = linear.As(&result); + if (FAILED(hr)) { + qWarning("%s: Could not convert Direct2D linear gradient brush: %#x", __FUNCTION__, hr); + break; + } + } + break; + case Qt::RadialGradientPattern: + if (newBrush.gradient()->spread() != QGradient::PadSpread) { + *needsEmulation = true; + } else { + ComPtr radial; + const QRadialGradient *qradial = static_cast(newBrush.gradient()); + + D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES radialGradientBrushProperties; + ComPtr gradientStopCollection; + + const QGradientStops &qstops = qradial->stops(); + QVector stops(qstops.count()); + + radialGradientBrushProperties.center = to_d2d_point_2f(qradial->center()); + radialGradientBrushProperties.gradientOriginOffset = to_d2d_point_2f(qradial->focalPoint() - qradial->center()); + radialGradientBrushProperties.radiusX = qradial->radius(); + radialGradientBrushProperties.radiusY = qradial->radius(); + + for (int i = 0; i < stops.size(); i++) { + stops[i].position = qstops[i].first; + stops[i].color = to_d2d_color_f(qstops[i].second); + } + + hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection); + if (FAILED(hr)) { + qWarning("%s: Could not create gradient stop collection for radial gradient: %#x", __FUNCTION__, hr); + break; + } + + hr = dc()->CreateRadialGradientBrush(radialGradientBrushProperties, gradientStopCollection.Get(), + &radial); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D radial gradient brush: %#x", __FUNCTION__, hr); + break; + } + + radial.As(&result); + if (FAILED(hr)) { + qWarning("%s: Could not convert Direct2D radial gradient brush: %#x", __FUNCTION__, hr); + break; + } + } + break; + case Qt::ConicalGradientPattern: *needsEmulation = true; break; @@ -706,16 +841,9 @@ QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap : QPaintEngineEx(*(new QWindowsDirect2DPaintEnginePrivate(bitmap))) { QPaintEngine::PaintEngineFeatures unsupported = - // As of 1.1 Direct2D gradient support is deficient for linear and radial gradients - QPaintEngine::LinearGradientFill - | QPaintEngine::RadialGradientFill - - // As of 1.1 Direct2D does not support conical gradients at all - | QPaintEngine::ConicalGradientFill - // As of 1.1 Direct2D does not natively support complex composition modes // However, using Direct2D effects that implement them should be possible - | QPaintEngine::PorterDuff + QPaintEngine::PorterDuff | QPaintEngine::BlendModes | QPaintEngine::RasterOpModes @@ -739,7 +867,7 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev) QPainterPath p; p.addRegion(systemClip()); - ComPtr geometry = painterPathToPathGeometry(p); + ComPtr geometry = painterPathToID2D1PathGeometry(p, d->antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED); if (!geometry) return false; @@ -761,6 +889,7 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev) D2D_TAG(D2DDebugDrawInitialStateTag); + setActive(true); return true; } @@ -768,7 +897,7 @@ bool QWindowsDirect2DPaintEngine::end() { Q_D(QWindowsDirect2DPaintEngine); // First pop any user-applied clipping - d->popClip(); + d->clearClips(); // Now the system clip from begin() above if (d->clipFlags & SimpleSystemClip) { d->dc()->PopAxisAlignedClip(); @@ -784,6 +913,23 @@ QPaintEngine::Type QWindowsDirect2DPaintEngine::type() const return QPaintEngine::Direct2D; } +void QWindowsDirect2DPaintEngine::setState(QPainterState *s) +{ + Q_D(QWindowsDirect2DPaintEngine); + + QPaintEngineEx::setState(s); + d->clearClips(); + + clipEnabledChanged(); + penChanged(); + brushChanged(); + brushOriginChanged(); + opacityChanged(); + compositionModeChanged(); + renderHintsChanged(); + transformChanged(); +} + void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &brush) { Q_D(QWindowsDirect2DPaintEngine); @@ -792,28 +938,10 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br if (path.isEmpty()) return; - d->updateBrush(brush); - - if (d->brush.emulate) { - // We mostly (only?) get here when gradients are required. - // We could probably natively support linear and radial gradients that have pad reflect - - QImage img(d->bitmap->size(), QImage::Format_ARGB32); - img.fill(Qt::transparent); - - QPainter p; - QPaintEngine *engine = img.paintEngine(); - if (engine->isExtended() && p.begin(&img)) { - QPaintEngineEx *extended = static_cast(engine); - extended->fill(path, brush); - if (!p.end()) - qWarning("%s: Paint Engine end returned false", __FUNCTION__); - - drawImage(img.rect(), img, img.rect()); - } else { - qWarning("%s: Could not fall back to QImage", __FUNCTION__); - } + ensureBrush(brush); + if (emulationRequired(BrushEmulation)) { + rasterFill(path, brush); return; } @@ -829,46 +957,22 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br d->dc()->FillGeometry(geometry.Get(), d->brush.brush.Get()); } -// For clipping we convert everything to painter paths since it allows -// calculating intersections easily. It might be faster to convert to -// ID2D1Geometry and use its operations, although that needs to measured. -// The implementation would be more complex in any case. - void QWindowsDirect2DPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) -{ - clip(path.convertToPainterPath(), op); -} - -void QWindowsDirect2DPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) -{ - QPainterPath p; - p.addRect(rect); - clip(p, op); -} - -void QWindowsDirect2DPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) -{ - QPainterPath p; - p.addRegion(region); - clip(p, op); -} - -void QWindowsDirect2DPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op) { Q_D(QWindowsDirect2DPaintEngine); - d->updateClipPath(path, op); + d->clip(path, op); } void QWindowsDirect2DPaintEngine::clipEnabledChanged() { Q_D(QWindowsDirect2DPaintEngine); - d->updateClipEnabled(); + d->updateClipEnabled(state()->clipEnabled); } void QWindowsDirect2DPaintEngine::penChanged() { Q_D(QWindowsDirect2DPaintEngine); - d->updatePen(); + d->updatePen(state()->pen); } void QWindowsDirect2DPaintEngine::brushChanged() @@ -880,19 +984,19 @@ void QWindowsDirect2DPaintEngine::brushChanged() void QWindowsDirect2DPaintEngine::brushOriginChanged() { Q_D(QWindowsDirect2DPaintEngine); - d->updateBrushOrigin(); + d->updateBrushOrigin(state()->brushOrigin); } void QWindowsDirect2DPaintEngine::opacityChanged() { Q_D(QWindowsDirect2DPaintEngine); - d->updateOpacity(); + d->updateOpacity(state()->opacity); } void QWindowsDirect2DPaintEngine::compositionModeChanged() { Q_D(QWindowsDirect2DPaintEngine); - d->updateCompositionMode(); + d->updateCompositionMode(state()->compositionMode()); } void QWindowsDirect2DPaintEngine::renderHintsChanged() @@ -904,7 +1008,199 @@ void QWindowsDirect2DPaintEngine::renderHintsChanged() void QWindowsDirect2DPaintEngine::transformChanged() { Q_D(QWindowsDirect2DPaintEngine); - d->updateTransform(); + d->updateTransform(state()->transform()); +} + +void QWindowsDirect2DPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugFillRectTag); + + ensureBrush(brush); + + if (emulationRequired(BrushEmulation)) { + QPaintEngineEx::fillRect(rect, brush); + } else { + QRectF r = rect.normalized(); + adjustForAliasing(&r); + + if (d->brush.brush) + d->dc()->FillRectangle(to_d2d_rect_f(rect), d->brush.brush.Get()); + } +} + +void QWindowsDirect2DPaintEngine::drawRects(const QRect *rects, int rectCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawRectsTag); + + ensureBrush(); + ensurePen(); + + if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) { + QPaintEngineEx::drawRects(rects, rectCount); + } else { + QRectF rect; + for (int i = 0; i < rectCount; i++) { + rect = rects[i].normalized(); + adjustForAliasing(&rect); + + D2D1_RECT_F d2d_rect = to_d2d_rect_f(rect); + + if (d->brush.brush) + d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } + } +} + +void QWindowsDirect2DPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawRectFsTag); + + ensureBrush(); + ensurePen(); + + if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) { + QPaintEngineEx::drawRects(rects, rectCount); + } else { + QRectF rect; + for (int i = 0; i < rectCount; i++) { + rect = rects[i].normalized(); + adjustForAliasing(&rect); + + D2D1_RECT_F d2d_rect = to_d2d_rect_f(rect); + + if (d->brush.brush) + d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } + } +} + +void QWindowsDirect2DPaintEngine::drawLines(const QLine *lines, int lineCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawLinesTag); + + ensurePen(); + + if (emulationRequired(PenEmulation)) { + QPaintEngineEx::drawLines(lines, lineCount); + } else if (d->pen.brush) { + for (int i = 0; i < lineCount; i++) { + QPointF p1 = lines[i].p1(); + QPointF p2 = lines[i].p2(); + + // Match raster engine output + if (p1 == p2 && d->pen.qpen.widthF() <= 1.0) { + fillRect(QRectF(p1, QSizeF(d->pen.qpen.widthF(), d->pen.qpen.widthF())), + d->pen.qpen.brush()); + continue; + } + + adjustForAliasing(&p1); + adjustForAliasing(&p2); + + D2D1_POINT_2F d2d_p1 = to_d2d_point_2f(p1); + D2D1_POINT_2F d2d_p2 = to_d2d_point_2f(p2); + + d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } + } +} + +void QWindowsDirect2DPaintEngine::drawLines(const QLineF *lines, int lineCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawLineFsTag); + + ensurePen(); + + if (emulationRequired(PenEmulation)) { + QPaintEngineEx::drawLines(lines, lineCount); + } else if (d->pen.brush) { + for (int i = 0; i < lineCount; i++) { + QPointF p1 = lines[i].p1(); + QPointF p2 = lines[i].p2(); + + // Match raster engine output + if (p1 == p2 && d->pen.qpen.widthF() <= 1.0) { + fillRect(QRectF(p1, QSizeF(d->pen.qpen.widthF(), d->pen.qpen.widthF())), + d->pen.qpen.brush()); + continue; + } + + adjustForAliasing(&p1); + adjustForAliasing(&p2); + + D2D1_POINT_2F d2d_p1 = to_d2d_point_2f(p1); + D2D1_POINT_2F d2d_p2 = to_d2d_point_2f(p2); + + d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } + } +} + +void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &r) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawEllipseFTag); + + ensureBrush(); + ensurePen(); + + if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) { + QPaintEngineEx::drawEllipse(r); + } else { + QPointF p = r.center(); + adjustForAliasing(&p); + + D2D1_ELLIPSE ellipse = { + to_d2d_point_2f(p), + r.width() / 2.0, + r.height() / 2.0 + }; + + if (d->brush.brush) + d->dc()->FillEllipse(ellipse, d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } +} + +void QWindowsDirect2DPaintEngine::drawEllipse(const QRect &r) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawEllipseTag); + + ensureBrush(); + ensurePen(); + + if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) { + QPaintEngineEx::drawEllipse(r); + } else { + QPointF p = r.center(); + adjustForAliasing(&p); + + D2D1_ELLIPSE ellipse = { + to_d2d_point_2f(p), + r.width() / 2.0, + r.height() / 2.0 + }; + + if (d->brush.brush) + d->dc()->FillEllipse(ellipse, d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } } void QWindowsDirect2DPaintEngine::drawImage(const QRectF &rectangle, const QImage &image, @@ -938,6 +1234,8 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, QWindowsDirect2DPlatformPixmap *pp = static_cast(pm.handle()); QWindowsDirect2DBitmap *bitmap = pp->bitmap(); + ensurePen(); + if (bitmap->bitmap() != d->bitmap->bitmap()) { // Good, src bitmap != dst bitmap if (sr.isValid()) @@ -1036,12 +1334,11 @@ void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticText Q_D(QWindowsDirect2DPaintEngine); D2D_TAG(D2DDebugDrawStaticTextItemTag); - if (qpen_style(d->pen.qpen) == Qt::NoPen) - return; - if (staticTextItem->numGlyphs == 0) return; + ensurePen(); + // If we can't support the current configuration with Direct2D, fall back to slow path // Most common cases are perspective transform and gradient brush as pen if ((state()->transform().isAffine() == false) || d->pen.emulate) { @@ -1086,13 +1383,12 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem Q_D(QWindowsDirect2DPaintEngine); D2D_TAG(D2DDebugDrawTextItemTag); - if (qpen_style(d->pen.qpen) == Qt::NoPen) - return; - const QTextItemInt &ti = static_cast(textItem); if (ti.glyphs.numGlyphs == 0) return; + ensurePen(); + // If we can't support the current configuration with Direct2D, fall back to slow path // Most common cases are perspective transform and gradient brush as pen if ((state()->transform().isAffine() == false) || d->pen.emulate) { @@ -1194,4 +1490,132 @@ void QWindowsDirect2DPaintEngine::drawGlyphRun(const D2D1_POINT_2F &pos, DWRITE_MEASURING_MODE_GDI_CLASSIC); } +void QWindowsDirect2DPaintEngine::ensureBrush() +{ + ensureBrush(state()->brush); +} + +void QWindowsDirect2DPaintEngine::ensureBrush(const QBrush &brush) +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateBrush(brush); +} + +void QWindowsDirect2DPaintEngine::ensurePen() +{ + ensurePen(state()->pen); +} + +void QWindowsDirect2DPaintEngine::ensurePen(const QPen &pen) +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updatePen(pen); +} + +void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBrush &brush) +{ + Q_D(QWindowsDirect2DPaintEngine); + + QImage img(d->bitmap->size(), QImage::Format_ARGB32); + img.fill(Qt::transparent); + + QPainter p; + QPaintEngine *engine = img.paintEngine(); + + if (engine->isExtended() && p.begin(&img)) { + p.setRenderHints(state()->renderHints); + p.setCompositionMode(state()->compositionMode()); + p.setOpacity(state()->opacity); + p.setBrushOrigin(state()->brushOrigin); + p.setBrush(state()->brush); + p.setPen(state()->pen); + + QPaintEngineEx *extended = static_cast(engine); + foreach (const QPainterClipInfo &info, state()->clipInfo) { + extended->state()->matrix = info.matrix; + extended->transformChanged(); + + switch (info.clipType) { + case QPainterClipInfo::RegionClip: + extended->clip(info.region, info.operation); + break; + case QPainterClipInfo::PathClip: + extended->clip(info.path, info.operation); + break; + case QPainterClipInfo::RectClip: + extended->clip(info.rect, info.operation); + break; + case QPainterClipInfo::RectFClip: + qreal right = info.rectf.x() + info.rectf.width(); + qreal bottom = info.rectf.y() + info.rectf.height(); + qreal pts[] = { info.rectf.x(), info.rectf.y(), + right, info.rectf.y(), + right, bottom, + info.rectf.x(), bottom }; + QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint); + extended->clip(vp, info.operation); + break; + } + } + + extended->state()->matrix = state()->matrix; + extended->transformChanged(); + + extended->fill(path, brush); + if (!p.end()) + qWarning("%s: Paint Engine end returned false", __FUNCTION__); + + d->updateClipEnabled(false); + d->updateTransform(QTransform()); + drawImage(img.rect(), img, img.rect()); + transformChanged(); + clipEnabledChanged(); + } else { + qWarning("%s: Could not fall back to QImage", __FUNCTION__); + } +} + +bool QWindowsDirect2DPaintEngine::emulationRequired(EmulationType type) const +{ + Q_D(const QWindowsDirect2DPaintEngine); + + if (!state()->matrix.isAffine()) + return true; + + switch (type) { + case PenEmulation: + return d->pen.emulate; + break; + case BrushEmulation: + return d->brush.emulate; + break; + } + + return false; +} + +bool QWindowsDirect2DPaintEngine::antiAliasingEnabled() const +{ + return state()->renderHints & QPainter::Antialiasing; +} + +void QWindowsDirect2DPaintEngine::adjustForAliasing(QRectF *rect) +{ + if (!antiAliasingEnabled()) { + rect->adjust(MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET); + } +} + +void QWindowsDirect2DPaintEngine::adjustForAliasing(QPointF *point) +{ + static const QPointF adjustment(MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET); + + if (!antiAliasingEnabled()) + (*point) += adjustment; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h index 6c74a07e88..badd7a7688 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -65,12 +65,10 @@ public: Type type() const Q_DECL_OVERRIDE; - void fill(const QVectorPath &path, const QBrush &brush) Q_DECL_OVERRIDE; + void setState(QPainterState *s) Q_DECL_OVERRIDE; + void fill(const QVectorPath &path, const QBrush &brush) Q_DECL_OVERRIDE; void clip(const QVectorPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE; - void clip(const QRect &rect, Qt::ClipOperation op) Q_DECL_OVERRIDE; - void clip(const QRegion ®ion, Qt::ClipOperation op) Q_DECL_OVERRIDE; - void clip(const QPainterPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE; void clipEnabledChanged() Q_DECL_OVERRIDE; void penChanged() Q_DECL_OVERRIDE; @@ -81,6 +79,17 @@ public: void renderHintsChanged() Q_DECL_OVERRIDE; void transformChanged() Q_DECL_OVERRIDE; + void fillRect(const QRectF &rect, const QBrush &brush) Q_DECL_OVERRIDE; + + void drawRects(const QRect *rects, int rectCount) Q_DECL_OVERRIDE; + void drawRects(const QRectF *rects, int rectCount) Q_DECL_OVERRIDE; + + void drawLines(const QLine *lines, int lineCount) Q_DECL_OVERRIDE; + void drawLines(const QLineF *lines, int lineCount) Q_DECL_OVERRIDE; + + void drawEllipse(const QRectF &r) Q_DECL_OVERRIDE; + void drawEllipse(const QRect &r) Q_DECL_OVERRIDE; + void drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE; void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE; @@ -91,6 +100,20 @@ private: void drawGlyphRun(const D2D1_POINT_2F &pos, IDWriteFontFace *fontFace, const QFont &font, int numGlyphs, const UINT16 *glyphIndices, const FLOAT *glyphAdvances, const DWRITE_GLYPH_OFFSET *glyphOffsets, bool rtl); + + void ensureBrush(); + void ensureBrush(const QBrush &brush); + void ensurePen(); + void ensurePen(const QPen &pen); + + void rasterFill(const QVectorPath &path, const QBrush &brush); + + enum EmulationType { PenEmulation, BrushEmulation }; + bool emulationRequired(EmulationType type) const; + + bool antiAliasingEnabled() const; + void adjustForAliasing(QRectF *rect); + void adjustForAliasing(QPointF *point); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index bf860f982e..50d0cb81f5 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -54,6 +54,9 @@ QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWi : QWindowsWindow(window, data) , m_needsFullFlush(true) { + if (window->type() == Qt::Desktop) + return; // No further handling for Qt::Desktop + DXGI_SWAP_CHAIN_DESC1 desc = {}; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; @@ -125,7 +128,7 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion } m_bitmap->deviceContext()->end(); - m_swapChain->Present(1, 0); + m_swapChain->Present(0, 0); } void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size) diff --git a/src/plugins/platforms/directfb/directfb.pro b/src/plugins/platforms/directfb/directfb.pro index ec4a612b52..89d8d42cea 100644 --- a/src/plugins/platforms/directfb/directfb.pro +++ b/src/plugins/platforms/directfb/directfb.pro @@ -2,6 +2,7 @@ TARGET = qdirectfb PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QDirectFbIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro index 8827f7680c..3ebe05b35e 100644 --- a/src/plugins/platforms/eglfs/eglfs.pro +++ b/src/plugins/platforms/eglfs/eglfs.pro @@ -2,6 +2,7 @@ TARGET = qeglfs PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QEglFSIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) SOURCES += $$PWD/main.cpp diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index c8c31816a0..f3fd06037e 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -91,7 +91,7 @@ private: Created = 0x01, HasNativeWindow = 0x02 }; - Q_DECLARE_FLAGS(Flags, Flag); + Q_DECLARE_FLAGS(Flags, Flag) Flags m_flags; }; diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index b7e074b95a..ffc4ff9b12 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -2,6 +2,7 @@ TARGET = qios PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QIOSIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 9a2c55f7f2..8be3846e06 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -229,6 +229,13 @@ [super touchesEnded:touches withEvent:event]; } +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ + m_touchPressWhileKeyboardVisible = NO; + [self performSelectorOnMainThread:@selector(touchesEndedPostDelivery) withObject:nil waitUntilDone:NO]; + [super touchesCancelled:touches withEvent:event]; +} + - (void)touchesEndedPostDelivery { // Do some clean-up _after_ touchEnd has been delivered to QUIView diff --git a/src/plugins/platforms/ios/quiview_textinput.mm b/src/plugins/platforms/ios/quiview_textinput.mm index 28fb23d57b..3f6c6d1256 100644 --- a/src/plugins/platforms/ios/quiview_textinput.mm +++ b/src/plugins/platforms/ios/quiview_textinput.mm @@ -473,6 +473,8 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables); QCoreApplication::sendEvent(focusObject, &e); QFont qfont = qvariant_cast(e.value(Qt::ImFont)); UIFont *uifont = [UIFont fontWithName:qfont.family().toNSString() size:qfont.pointSize()]; + if (!uifont) + return [NSDictionary dictionary]; return [NSDictionary dictionaryWithObject:uifont forKey:UITextInputTextFontKey]; } diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro index 1b3678f13a..baa8778153 100644 --- a/src/plugins/platforms/kms/kms.pro +++ b/src/plugins/platforms/kms/kms.pro @@ -2,6 +2,7 @@ TARGET = qkms PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QKmsIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro index 9e9f9b29b7..389d45c29c 100644 --- a/src/plugins/platforms/linuxfb/linuxfb.pro +++ b/src/plugins/platforms/linuxfb/linuxfb.pro @@ -2,6 +2,7 @@ TARGET = qlinuxfb PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QLinuxFbIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro index 3131b16232..3ed4d2cdde 100644 --- a/src/plugins/platforms/minimal/minimal.pro +++ b/src/plugins/platforms/minimal/minimal.pro @@ -2,6 +2,7 @@ TARGET = qminimal PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/minimalegl/minimalegl.pro b/src/plugins/platforms/minimalegl/minimalegl.pro index 00c83eb1ca..e78dcb8bc5 100644 --- a/src/plugins/platforms/minimalegl/minimalegl.pro +++ b/src/plugins/platforms/minimalegl/minimalegl.pro @@ -2,6 +2,7 @@ TARGET = qminimalegl PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QMinimalEglIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index 5db5e32e65..94eeac6acc 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -2,6 +2,7 @@ TARGET = qoffscreen PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QOffscreenIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/openwfd/openwf.pro b/src/plugins/platforms/openwfd/openwf.pro index 2dbcb282db..38bac057bd 100644 --- a/src/plugins/platforms/openwfd/openwf.pro +++ b/src/plugins/platforms/openwfd/openwf.pro @@ -2,6 +2,7 @@ TARGET = qopenwf PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QOpenWFDIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 04c6087cd1..856b7d2abe 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -161,4 +161,5 @@ include (../../../platformsupport/fontdatabases/fontdatabases.pri) PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QQnxIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h index e83fc445d6..83af966a00 100644 --- a/src/plugins/platforms/qnx/qqnxfiledialoghelper.h +++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper.h @@ -88,7 +88,9 @@ Q_SIGNALS: void dialogClosed(); private Q_SLOTS: +#if !defined(Q_OS_BLACKBERRY_TABLET) void emitSignals(); +#endif private: void setNameFilter(const QString &filter); diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp index eb9fac540f..ead6e73a87 100644 --- a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp @@ -64,10 +64,13 @@ QQnxRasterWindow::QQnxRasterWindow(QWindow *window, screen_context_t context, bo initWindow(); // Set window usage + if (window->type() == Qt::Desktop) + return; + const int val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE; const int result = screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_USAGE, &val); if (result != 0) - qFatal("QQnxEglWindow: failed to set window alpha usage, errno=%d", errno); + qFatal("QQnxRasterWindow: failed to set window alpha usage, errno=%d", errno); } void QQnxRasterWindow::post(const QRegion &dirty) diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index 2707f14db2..9ba0f5cd2e 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -97,9 +97,9 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { const int envHeight = envPhySizeStrList.size() == 2 ? envPhySizeStrList[1].toInt() : -1; if (envWidth <= 0 || envHeight <= 0) { - qFatal("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format " - "\"width,height\" in mm, with width, height > 0. " - "Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90"); + qWarning("QQnxScreen: The value of QQNX_PHYSICAL_SCREEN_SIZE must be in the format " + "\"width,height\" in mm, with width, height > 0. Defaulting to 150x90. " + "Example: QQNX_PHYSICAL_SCREEN_SIZE=150,90"); return QSize(150, 90); } @@ -114,8 +114,8 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { return defSize; #else if (primaryScreen) - qFatal("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. " - "Could not determine physical screen size."); + qWarning("QQnxScreen: QQNX_PHYSICAL_SCREEN_SIZE variable not set. " + "Could not determine physical screen size. Defaulting to 150x90."); return QSize(150, 90); #endif } diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 2e0febff20..5a405f9577 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -174,7 +174,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW // indication that we want to create a child window and join that window group. const QVariant windowGroup = window->property("qnxInitialWindowGroup"); - if (window->type() == Qt::CoverWindow || window->type() == Qt::Desktop) { + if (window->type() == Qt::CoverWindow) { // Cover windows have to be top level to be accessible to window delegate (i.e. navigator) // Desktop windows also need to be toplevel because they are not // supposed to be part of the window hierarchy tree @@ -189,10 +189,13 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW m_isTopLevel = !needRootWindow || !platformScreen->rootWindow(); } + if (window->type() == Qt::Desktop) // A desktop widget does not need a libscreen window + return; + if (m_isTopLevel) { Q_SCREEN_CRITICALERROR(screen_create_window(&m_window, m_screenContext), "Could not create top level window"); // Creates an application window - if (window->type() != Qt::CoverWindow && window->type() != Qt::Desktop) { + if (window->type() != Qt::CoverWindow) { if (needRootWindow) platformScreen->setRootWindow(this); } @@ -245,9 +248,9 @@ void QQnxWindow::setGeometry(const QRect &rect) if (shouldMakeFullScreen()) newGeometry = screen()->geometry(); - setGeometryHelper(newGeometry); + if (window()->type() != Qt::Desktop) + setGeometryHelper(newGeometry); - QWindowSystemInterface::handleGeometryChange(window(), newGeometry); if (isExposed()) QWindowSystemInterface::handleExposeEvent(window(), newGeometry); } @@ -278,13 +281,15 @@ void QQnxWindow::setGeometryHelper(const QRect &rect) "Failed to set window source size"); screen_flush_context(m_screenContext, 0); + + QWindowSystemInterface::handleGeometryChange(window(), rect); } void QQnxWindow::setVisible(bool visible) { qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "visible =" << visible; - if (m_visible == visible) + if (m_visible == visible || window()->type() == Qt::Desktop) return; // The first time through we join a window group if appropriate. @@ -667,6 +672,9 @@ void QQnxWindow::setRotation(int rotation) void QQnxWindow::initWindow() { + if (window()->type() == Qt::Desktop) + return; + // Alpha channel is always pre-multiplied if present int val = SCREEN_PRE_MULTIPLIED_ALPHA; Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val), @@ -711,12 +719,7 @@ void QQnxWindow::initWindow() if (window()->parent() && window()->parent()->handle()) setParent(window()->parent()->handle()); - if (shouldMakeFullScreen()) - setGeometryHelper(screen()->geometry()); - else - setGeometryHelper(window()->geometry()); - - QWindowSystemInterface::handleGeometryChange(window(), screen()->geometry()); + setGeometryHelper(shouldMakeFullScreen() ? screen()->geometry() : window()->geometry()); } void QQnxWindow::createWindowGroup() diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index 9a2006396f..94df903336 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -75,7 +75,7 @@ public: bool isExposed() const; - WId winId() const { return (WId)m_window; } + WId winId() const { return window()->type() == Qt::Desktop ? -1 : (WId)m_window; } screen_window_t nativeHandle() const { return m_window; } void setBufferSize(const QSize &size); diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 7643177395..ccff2d3e9f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Samuel Gaist -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -49,11 +49,11 @@ #include "qwindowsmime.h" #include "qwindowsinputcontext.h" #include "qwindowstabletsupport.h" +#include #ifndef QT_NO_ACCESSIBILITY # include "accessible/qwindowsaccessibility.h" #endif #if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER) -# include # include # include "qwindowssessionmanager.h" #endif @@ -76,6 +76,9 @@ #include #include #include +#ifndef Q_OS_WINCE +# include +#endif QT_BEGIN_NAMESPACE @@ -213,7 +216,7 @@ bool QWindowsUser32DLL::initTouch() unregisterTouchWindow = (UnregisterTouchWindow)(library.resolve("UnregisterTouchWindow")); getTouchInputInfo = (GetTouchInputInfo)(library.resolve("GetTouchInputInfo")); closeTouchInputHandle = (CloseTouchInputHandle)(library.resolve("CloseTouchInputHandle")); - return registerTouchWindow && unregisterTouchWindow && getTouchInputInfo && getTouchInputInfo; + return registerTouchWindow && unregisterTouchWindow && getTouchInputInfo && closeTouchInputHandle; } /*! @@ -325,6 +328,10 @@ QWindowsContextPrivate::QWindowsContextPrivate() m_systemInfo |= QWindowsContext::SI_RTL_Extensions; m_keyMapper.setUseRTLExtensions(true); } + if (FAILED(m_oleInitializeResult)) { + qWarning() << "QWindowsContext: OleInitialize() failed: " + << QWindowsContext::comErrorString(m_oleInitializeResult); + } } QWindowsContext::QWindowsContext() : @@ -734,45 +741,70 @@ HWND QWindowsContext::createDummyWindow(const QString &classNameIn, QByteArray QWindowsContext::comErrorString(HRESULT hr) { + QByteArray result = QByteArrayLiteral("COM error 0x") + + QByteArray::number(quintptr(hr), 16) + ' '; switch (hr) { case S_OK: - return QByteArrayLiteral("S_OK"); + result += QByteArrayLiteral("S_OK"); + break; case S_FALSE: - return QByteArrayLiteral("S_FALSE"); + result += QByteArrayLiteral("S_FALSE"); + break; case E_UNEXPECTED: - return QByteArrayLiteral("E_UNEXPECTED"); + result += QByteArrayLiteral("E_UNEXPECTED"); + break; case CO_E_ALREADYINITIALIZED: - return QByteArrayLiteral("CO_E_ALREADYINITIALIZED"); + result += QByteArrayLiteral("CO_E_ALREADYINITIALIZED"); + break; case CO_E_NOTINITIALIZED: - return QByteArrayLiteral("CO_E_NOTINITIALIZED"); + result += QByteArrayLiteral("CO_E_NOTINITIALIZED"); + break; case RPC_E_CHANGED_MODE: - return QByteArrayLiteral("RPC_E_CHANGED_MODE"); + result += QByteArrayLiteral("RPC_E_CHANGED_MODE"); + break; case OLE_E_WRONGCOMPOBJ: - return QByteArrayLiteral("OLE_E_WRONGCOMPOBJ"); + result += QByteArrayLiteral("OLE_E_WRONGCOMPOBJ"); + break; case CO_E_NOT_SUPPORTED: - return QByteArrayLiteral("CO_E_NOT_SUPPORTED"); + result += QByteArrayLiteral("CO_E_NOT_SUPPORTED"); + break; case E_NOTIMPL: - return QByteArrayLiteral("E_NOTIMPL"); + result += QByteArrayLiteral("E_NOTIMPL"); + break; case E_INVALIDARG: - return QByteArrayLiteral("E_INVALIDARG"); + result += QByteArrayLiteral("E_INVALIDARG"); + break; case E_NOINTERFACE: - return QByteArrayLiteral("E_NOINTERFACE"); + result += QByteArrayLiteral("E_NOINTERFACE"); + break; case E_POINTER: - return QByteArrayLiteral("E_POINTER"); + result += QByteArrayLiteral("E_POINTER"); + break; case E_HANDLE: - return QByteArrayLiteral("E_HANDLE"); + result += QByteArrayLiteral("E_HANDLE"); + break; case E_ABORT: - return QByteArrayLiteral("E_ABORT"); + result += QByteArrayLiteral("E_ABORT"); + break; case E_FAIL: - return QByteArrayLiteral("E_FAIL"); + result += QByteArrayLiteral("E_FAIL"); + break; case RPC_E_WRONG_THREAD: - return QByteArrayLiteral("RPC_E_WRONG_THREAD"); + result += QByteArrayLiteral("RPC_E_WRONG_THREAD"); + break; case RPC_E_THREAD_NOT_INIT: - return QByteArrayLiteral("RPC_E_THREAD_NOT_INIT"); + result += QByteArrayLiteral("RPC_E_THREAD_NOT_INIT"); + break; default: break; } - return "Unknown error 0x" + QByteArray::number(quint64(hr), 16); +#ifndef Q_OS_WINCE + _com_error error(hr); + result += QByteArrayLiteral(" ("); + result += QString::fromWCharArray(error.ErrorMessage()).toLocal8Bit(); + result += ')'; +#endif // !Q_OS_WINCE + return result; } /*! @@ -1068,6 +1100,21 @@ void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et, { QWindow *nextActiveWindow = 0; if (et == QtWindows::FocusInEvent) { + QWindow *topWindow = QWindowsWindow::topLevelOf(platformWindow->window()); + QWindow *modalWindow = 0; + if (QGuiApplicationPrivate::instance()->isWindowBlocked(topWindow, &modalWindow) && topWindow != modalWindow) { + modalWindow->requestActivate(); + return; + } + // QTBUG-32867: Invoking WinAPI SetParent() can cause focus-in for the + // window which is not desired for native child widgets. + if (platformWindow->testFlag(QWindowsWindow::WithinSetParent)) { + QWindow *currentFocusWindow = QGuiApplication::focusWindow(); + if (currentFocusWindow && currentFocusWindow != platformWindow->window()) { + currentFocusWindow->requestActivate(); + return; + } + } nextActiveWindow = platformWindow->window(); } else { // Focus out: Is the next window known and different diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 1432dfdcd9..940d75614c 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -1040,7 +1040,11 @@ QWindowsFontDatabase::~QWindowsFontDatabase() QFontEngineMulti *QWindowsFontDatabase::fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) { - return new QWindowsMultiFontEngine(fontEngine, script); + if (script == QChar::Script_Common) + return new QWindowsMultiFontEngine(fontEngine, script); + // ### as long as fallbacksForFamily() does not take script parameter into account, + // prefer QFontEngineMultiQPA's loadEngine() implementation for complex scripts + return QPlatformFontDatabase::fontEngineMulti(fontEngine, script); } QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) @@ -1619,8 +1623,7 @@ QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFon result << QString::fromLatin1("Arial"); } - if (script == QChar::Script_Common || script == QChar::Script_Han) - result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); + result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint << script << result << m_families.size(); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 51961014d9..734f645e65 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -477,8 +477,7 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF } #endif - if (script == QChar::Script_Common || script == QChar::Script_Han) - result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); + result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint << script << result << m_families; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 4f3a007bd7..29c43fc7a5 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -1032,7 +1032,7 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int iw = gm.width.toInt(); int ih = gm.height.toInt(); - if (iw <= 0 || iw <= 0) + if (iw <= 0 || ih <= 0) return 0; bool has_transformation = t.type() > QTransform::TxTranslate; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 0be9f5c626..aed7ad9c46 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -250,7 +250,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return true; case ThreadedOpenGL: #if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - return QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL + return QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL ? QWindowsEGLContext::hasThreadedOpenGLCapability() : true; # else return true; @@ -315,7 +315,7 @@ QPlatformOpenGLContext { qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); #if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { if (d->m_staticEGLContext.isNull()) { QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create(); if (!staticContext) @@ -326,7 +326,7 @@ QPlatformOpenGLContext } #endif #if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { if (d->m_staticOpenGLContext.isNull()) d->m_staticOpenGLContext = QSharedPointer(QOpenGLStaticContext::create()); diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index 7e15be1d19..06c0122bbb 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -125,7 +125,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour return 0; } #if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { QWindowsEGLContext *windowsEglContext = static_cast(context->handle()); if (resource == QByteArrayLiteral("eglDisplay")) return windowsEglContext->eglDisplay(); @@ -136,7 +136,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour } #endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC #if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { QWindowsGLContext *windowsContext = static_cast(context->handle()); if (resource == QByteArrayLiteral("renderingContext")) return windowsContext->renderingContext(); diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 6349c1e355..6a3930dc78 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -230,12 +230,16 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette) result.setColor(QPalette::All, QPalette::Text, tipTextColor); result.setColor(QPalette::All, QPalette::WindowText, tipTextColor); result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor); + result.setColor(QPalette::All, QPalette::ToolTipBase, tipBgColor); + result.setColor(QPalette::All, QPalette::ToolTipText, tipTextColor); const QColor disabled = mixColors(result.foreground().color(), result.button().color()); result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled); + result.setColor(QPalette::Disabled, QPalette::ToolTipText, disabled); result.setColor(QPalette::Disabled, QPalette::Base, Qt::white); result.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white); + result.setColor(QPalette::Disabled, QPalette::ToolTipBase, Qt::white); return result; } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 00229a7540..2a221e71ca 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -886,7 +886,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) if (aWindow->surfaceType() == QWindow::OpenGLSurface) { setFlag(OpenGLSurface); #if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) + if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) setFlag(OpenGL_ES2); #endif } @@ -1022,17 +1022,17 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w) while (QWindow *parent = w->parent()) w = parent; - const QWindowsWindow *ww = static_cast(w->handle()); - - // In case the topmost parent is embedded, find next ancestor using native methods - if (ww->isEmbedded(0)) { - HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT); - const HWND desktopHwnd = GetDesktopWindow(); - const QWindowsContext *ctx = QWindowsContext::instance(); - while (parentHWND && parentHWND != desktopHwnd) { - if (QWindowsWindow *ancestor = ctx->findPlatformWindow(parentHWND)) - return topLevelOf(ancestor->window()); - parentHWND = GetAncestor(parentHWND, GA_PARENT); + if (const QPlatformWindow *handle = w->handle()) { + const QWindowsWindow *ww = static_cast(handle); + if (ww->isEmbedded(0)) { + HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT); + const HWND desktopHwnd = GetDesktopWindow(); + const QWindowsContext *ctx = QWindowsContext::instance(); + while (parentHWND && parentHWND != desktopHwnd) { + if (QWindowsWindow *ancestor = ctx->findPlatformWindow(parentHWND)) + return topLevelOf(ancestor->window()); + parentHWND = GetAncestor(parentHWND, GA_PARENT); + } } } return w; diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 188bd7917c..cc0373c077 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -2,6 +2,7 @@ TARGET = qwindows PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWindowsIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT *= core-private diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 2e38f81499..583441f396 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1020,7 +1020,9 @@ HRESULT QWinRTScreen::onOrientationChanged(IInspectable *) HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) { QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); + QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); backPress.setAccepted(false); + backRelease.setAccepted(false); QObject *receiver = m_visibleWindows.isEmpty() ? static_cast(QGuiApplication::instance()) @@ -1028,12 +1030,8 @@ HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs // If the event is ignored, the app will suspend QGuiApplication::sendEvent(receiver, &backPress); - if (backPress.isAccepted()) { - args->put_Handled(true); - // If the app accepts the event, send the release for symmetry - QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); - QGuiApplication::sendEvent(receiver, &backRelease); - } + QGuiApplication::sendEvent(receiver, &backRelease); + args->put_Handled(backPress.isAccepted() || backRelease.isAccepted()); return S_OK; } diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 60c87bb61a..0122bf9475 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -12,6 +12,7 @@ winphone { PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index de907f87df..30d5c911e7 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -574,12 +574,32 @@ bool QGLXContext::m_supportsThreading = true; // binary search. static const char *qglx_threadedgl_blacklist_renderer[] = { "Chromium", // QTBUG-32225 (initialization fails) - "Mesa DRI Intel(R) Sandybridge Mobile", // QTBUG-34492 (flickering in fullscreen) 0 }; +// This disables threaded rendering on anything using mesa, e.g. +// - nvidia/nouveau +// - amd/gallium +// - intel +// - some software opengl implementations +// +// The client glx vendor string is used to identify those setups as that seems to show the least +// variance between the bad configurations. It's always "Mesa Project and SGI". There are some +// configurations which don't use mesa and which can do threaded rendering (amd and nvidia chips +// with their own proprietary drivers). +// +// This, of course, is very broad and disables threaded rendering on a lot of devices which would +// be able to use it. However, the bugs listed below don't follow any easily recognizable pattern +// and we should rather be safe. +// +// http://cgit.freedesktop.org/xcb/libxcb/commit/?id=be0fe56c3bcad5124dcc6c47a2fad01acd16f71a will +// fix some of the issues. Basically, the proprietary drivers seem to have a way of working around +// a fundamental flaw with multithreaded access to xcb, but mesa doesn't. The blacklist should be +// reevaluated once that patch is released in some version of xcb. static const char *qglx_threadedgl_blacklist_vendor[] = { - "nouveau", // QTCREATORBUG-10875 (crash in creator) + "Mesa Project and SGI", // QTCREATORBUG-10875 (crash in creator) + // QTBUG-34492 (flickering in fullscreen) + // QTBUG-38221 0 }; @@ -627,9 +647,9 @@ void QGLXContext::queryDummyContext() } } - if (const char *vendor = (const char *) glGetString(GL_VENDOR)) { + if (glxvendor) { for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) { - if (strstr(vendor, qglx_threadedgl_blacklist_vendor[i]) != 0) { + if (strstr(glxvendor, qglx_threadedgl_blacklist_vendor[i]) != 0) { m_supportsThreading = false; break; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index f5f6c712c5..e3b81c2b40 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1791,6 +1791,19 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub return true; } +bool QXcbConnection::xi2GetButtonState(void *event, int buttonNum) +{ + xXIDeviceEvent *xideviceevent = static_cast(event); + unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1]; + + for (int i = 0; i < (xideviceevent->buttons_len * 4); i++) { + if (buttonNum < 8) + return (buttonsMaskAddr[i] & (1 << buttonNum)); + buttonNum -= 8; + } + return false; +} + // Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: // - "pad0" became "extension" // - "pad1" and "pad" became "pad0" diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index c5fe2e33d5..1719d8ec6b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -402,6 +402,12 @@ public: #elif defined(XCB_USE_XINPUT2) void xi2Select(xcb_window_t window); #endif +#ifdef XCB_USE_XINPUT21 + bool isUsingXInput21() { return m_xi2Enabled && m_xi2Minor >= 1; } +#else + bool isUsingXInput21() { return false; } +#endif + void sync(); void flush() { xcb_flush(m_connection); } @@ -455,6 +461,10 @@ public: QXcbSystemTrayTracker *systemTrayTracker(); +#ifdef XCB_USE_XINPUT2 + void handleEnterEvent(const xcb_enter_notify_event_t *); +#endif + private slots: void processXcbEvents(); @@ -508,11 +518,12 @@ private: QVector m_tabletData; #endif struct ScrollingDevice { - ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0) { } + ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { } int deviceId; int verticalIndex, horizontalIndex; double verticalIncrement, horizontalIncrement; Qt::Orientations orientations; + Qt::Orientations legacyOrientations; QPointF lastScrollPosition; }; void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice); @@ -522,6 +533,7 @@ private: #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value); static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode); + static bool xi2GetButtonState(void *event, int buttonNum); #endif xcb_connection_t *m_connection; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index d80b49ccbb..831ccba6f6 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -134,7 +134,6 @@ void QXcbConnection::initializeXInput2() #ifdef XCB_USE_XINPUT21 case XIScrollClass: { XIScrollClassInfo *sci = reinterpret_cast(devices[i].classes[c]); - scrollingDevice.deviceId = devices[i].deviceid; if (sci->scroll_type == XIScrollTypeVertical) { scrollingDevice.orientations |= Qt::Vertical; scrollingDevice.verticalIndex = sci->number; @@ -147,6 +146,20 @@ void QXcbConnection::initializeXInput2() } break; } + case XIButtonClass: { + XIButtonClassInfo *bci = reinterpret_cast(devices[i].classes[c]); + for (int i=0; i < bci->num_buttons; ++i) { + const int buttonAtom = qatom(bci->labels[i]); + if (buttonAtom == QXcbAtom::ButtonWheelUp + || buttonAtom == QXcbAtom::ButtonWheelDown) { + scrollingDevice.legacyOrientations |= Qt::Vertical; + } else if (buttonAtom == QXcbAtom::ButtonHorizWheelLeft + || buttonAtom == QXcbAtom::ButtonHorizWheelRight) { + scrollingDevice.legacyOrientations |= Qt::Horizontal; + } + } + break; + } #endif default: break; @@ -170,7 +183,10 @@ void QXcbConnection::initializeXInput2() #endif // QT_NO_TABLETEVENT #ifdef XCB_USE_XINPUT21 - if (scrollingDevice.orientations) { + if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) { + scrollingDevice.deviceId = devices[i].deviceid; + // Only use legacy wheel button events when we don't have real scroll valuators. + scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations; m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice); if (Q_UNLIKELY(debug_xinput_devices)) qDebug() << " it's a scrolling device"; @@ -256,6 +272,7 @@ void QXcbConnection::xi2Select(xcb_window_t window) if (!m_scrollingDevices.isEmpty()) { QVector xiEventMask(m_scrollingDevices.size()); bitMask = XI_MotionMask; + bitMask |= XI_ButtonReleaseMask; int i=0; Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) { xiEventMask[i].deviceid = scrollingDevice.deviceId; @@ -524,6 +541,35 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) } } +void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *) +{ +#ifdef XCB_USE_XINPUT21 + QHash::iterator it = m_scrollingDevices.begin(); + const QHash::iterator end = m_scrollingDevices.end(); + while (it != end) { + ScrollingDevice& scrollingDevice = it.value(); + int nrDevices = 0; + XIDeviceInfo* xiDeviceInfo = XIQueryDevice(static_cast(m_xlib_display), scrollingDevice.deviceId, &nrDevices); + if (nrDevices <= 0) { + it = m_scrollingDevices.erase(it); + continue; + } + for (int c = 0; c < xiDeviceInfo->num_classes; ++c) { + if (xiDeviceInfo->classes[c]->type == XIValuatorClass) { + XIValuatorClassInfo *vci = reinterpret_cast(xiDeviceInfo->classes[c]); + const int valuatorAtom = qatom(vci->label); + if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel) + scrollingDevice.lastScrollPosition.setX(vci->value); + else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel) + scrollingDevice.lastScrollPosition.setY(vci->value); + } + } + XIFreeDeviceInfo(xiDeviceInfo); + ++it; + } +#endif +} + void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice) { #ifdef XCB_USE_XINPUT21 @@ -566,6 +612,31 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers); } } + } else if (xiEvent->evtype == XI_ButtonRelease) { + xXIDeviceEvent* xiDeviceEvent = reinterpret_cast(event); + if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { + QPoint angleDelta; + if (scrollingDevice.legacyOrientations & Qt::Vertical) { + if (xi2GetButtonState(xiDeviceEvent, 4)) + angleDelta.setY(120); + else if (xi2GetButtonState(xiDeviceEvent, 5)) + angleDelta.setY(-120); + } + if (scrollingDevice.legacyOrientations & Qt::Horizontal) { + if (xi2GetButtonState(xiDeviceEvent, 6)) + angleDelta.setX(120); + if (xi2GetButtonState(xiDeviceEvent, 7)) + angleDelta.setX(-120); + } + if (!angleDelta.isNull()) { + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); + Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); + if (modifiers & Qt::AltModifier) + std::swap(angleDelta.rx(), angleDelta.ry()); + QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, QPoint(), angleDelta, modifiers); + } + } } #else Q_UNUSED(event); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5a2002f1d4..3645b6469a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -485,7 +485,7 @@ QXcbWindow::~QXcbWindow() void QXcbWindow::destroy() { if (connection()->focusWindow() == this) - connection()->setFocusWindow(0); + doFocusOut(); if (m_syncCounter && m_usingSyncProtocol) Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter)); @@ -554,7 +554,7 @@ QMargins QXcbWindow::frameMargins() const xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection(), cookie, NULL); if (reply) { - if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1) { + if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1 || reply->parent == XCB_WINDOW_NONE) { foundRoot = true; } else { window = parent; @@ -671,6 +671,9 @@ void QXcbWindow::show() Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); + if (QGuiApplication::modalWindow() == window()) + requestActivateWindow(); + m_screen->windowShown(this); connection()->sync(); @@ -694,6 +697,68 @@ void QXcbWindow::hide() m_mapped = false; } +static QWindow *tlWindow(QWindow *window) +{ + if (window && window->parent()) + return tlWindow(window->parent()); + return window; +} + +bool QXcbWindow::relayFocusToModalWindow() const +{ + QWindow *w = tlWindow(static_cast(QObjectPrivate::get(window()))->eventReceiver()); + QWindow *modal_window = 0; + if (QGuiApplicationPrivate::instance()->isWindowBlocked(w,&modal_window) && modal_window != w) { + modal_window->requestActivate(); + connection()->flush(); + return true; + } + + return false; +} + +void QXcbWindow::doFocusIn() +{ + if (relayFocusToModalWindow()) + return; + QWindow *w = static_cast(QObjectPrivate::get(window()))->eventReceiver(); + connection()->setFocusWindow(static_cast(w->handle())); + QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason); +} + +static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event) +{ + if (!event) { + // FocusIn event is not in the queue, proceed with FocusOut normally. + QWindowSystemInterface::handleWindowActivated(0, Qt::ActiveWindowFocusReason); + return true; + } + uint response_type = event->response_type & ~0x80; + if (response_type == XCB_FOCUS_IN) + return true; + + /* We are also interested in XEMBED_FOCUS_IN events */ + if (response_type == XCB_CLIENT_MESSAGE) { + xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event; + if (cme->type == connection->atom(QXcbAtom::_XEMBED) + && cme->data.data32[1] == XEMBED_FOCUS_IN) + return true; + } + + return false; +} + +void QXcbWindow::doFocusOut() +{ + if (relayFocusToModalWindow()) + return; + connection()->setFocusWindow(0); + // Do not set the active window to 0 if there is a FocusIn coming. + // There is however no equivalent for XPutBackEvent so register a + // callback for QXcbConnection instead. + connection()->addPeekFunc(focusInPeeker); +} + struct QtMotifWmHints { quint32 flags, functions, decorations; qint32 input_mode; @@ -1514,6 +1579,8 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even QWindowSystemInterface::handleCloseEvent(window()); } else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) { connection()->setTime(event->data.data32[1]); + relayFocusToModalWindow(); + return; } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) { if (event->window == m_screen->root()) return; @@ -1549,8 +1616,7 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } else if (event->type == atom(QXcbAtom::_XEMBED)) { handleXEmbedMessage(event); } else if (event->type == atom(QXcbAtom::_NET_ACTIVE_WINDOW)) { - connection()->setFocusWindow(this); - QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason); + doFocusIn(); } else if (event->type == atom(QXcbAtom::MANAGER) || event->type == atom(QXcbAtom::_NET_WM_STATE) || event->type == atom(QXcbAtom::WM_CHANGE_STATE)) { @@ -1705,16 +1771,16 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); if (isWheel) { -#ifndef XCB_USE_XINPUT21 - // Logic borrowed from qapplication_x11.cpp - int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1); - bool hor = (((event->detail == 4 || event->detail == 5) - && (modifiers & Qt::AltModifier)) - || (event->detail == 6 || event->detail == 7)); + if (!connection()->isUsingXInput21()) { + // Logic borrowed from qapplication_x11.cpp + int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1); + bool hor = (((event->detail == 4 || event->detail == 5) + && (modifiers & Qt::AltModifier)) + || (event->detail == 6 || event->detail == 7)); - QWindowSystemInterface::handleWheelEvent(window(), event->time, - local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers); -#endif + QWindowSystemInterface::handleWheelEvent(window(), event->time, + local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers); + } return; } @@ -1778,6 +1844,9 @@ public: void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) { connection()->setTime(event->time); +#ifdef XCB_USE_XINPUT2 + connection()->handleEnterEvent(event); +#endif if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB) || event->detail == XCB_NOTIFY_DETAIL_VIRTUAL @@ -1865,41 +1934,13 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *) { - QWindow *w = window(); - w = static_cast(QObjectPrivate::get(w))->eventReceiver(); - connection()->setFocusWindow(static_cast(w->handle())); - QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason); + doFocusIn(); } -static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event) -{ - if (!event) { - // FocusIn event is not in the queue, proceed with FocusOut normally. - QWindowSystemInterface::handleWindowActivated(0, Qt::ActiveWindowFocusReason); - return true; - } - uint response_type = event->response_type & ~0x80; - if (response_type == XCB_FOCUS_IN) - return true; - - /* We are also interested in XEMBED_FOCUS_IN events */ - if (response_type == XCB_CLIENT_MESSAGE) { - xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event; - if (cme->type == connection->atom(QXcbAtom::_XEMBED) - && cme->data.data32[1] == XEMBED_FOCUS_IN) - return true; - } - - return false; -} void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *) { - connection()->setFocusWindow(0); - // Do not set the active window to 0 if there is a FocusIn coming. - // There is however no equivalent for XPutBackEvent so register a - // callback for QXcbConnection instead. - connection()->addPeekFunc(focusInPeeker); + doFocusOut(); } void QXcbWindow::updateSyncRequestCounter() diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index a90ad7b5ed..12d17023fb 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -176,6 +176,10 @@ private: void show(); void hide(); + bool relayFocusToModalWindow() const; + void doFocusIn(); + void doFocusOut(); + QXcbScreen *m_screen; xcb_window_t m_window; diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 9e4e997f55..a52aaa4a2e 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -2,6 +2,7 @@ TARGET = qxcb PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QXcbIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/printsupport/windows/windows.pro b/src/plugins/printsupport/windows/windows.pro index 364e19e68e..3366262ef0 100644 --- a/src/plugins/printsupport/windows/windows.pro +++ b/src/plugins/printsupport/windows/windows.pro @@ -21,4 +21,4 @@ HEADERS += \ OTHER_FILES += windows.json -LIBS += -lwinspool -lcomdlg32 +LIBS += -lwinspool -lcomdlg32 -lgdi32 -luser32 diff --git a/src/printsupport/dialogs/qprintdialog_mac.mm b/src/printsupport/dialogs/qprintdialog_mac.mm index 9ff7c4766a..ef3e88be39 100644 --- a/src/printsupport/dialogs/qprintdialog_mac.mm +++ b/src/printsupport/dialogs/qprintdialog_mac.mm @@ -143,11 +143,11 @@ QT_USE_NAMESPACE CFURLGetFileSystemRepresentation(file, true, localFile, sizeof(localFile)); printer->setOutputFileName(QString::fromUtf8(reinterpret_cast(localFile))); } else { - // Keep output format. - QPrinter::OutputFormat format; - format = printer->outputFormat(); - printer->setOutputFileName(QString()); - printer->setOutputFormat(format); + PMPrinter macPrinter; + PMSessionGetCurrentPrinter(session, &macPrinter); + QString printerId = QString::fromCFString(PMPrinterGetID(macPrinter)); + if (printer->printerName() != printerId) + printer->setPrinterName(printerId); } } @@ -160,13 +160,13 @@ QT_USE_NAMESPACE PMOrientation orientation; PMGetOrientation(pageFormat, &orientation); QPageSize pageSize; - QCFString key; + CFStringRef key; double width = 0; double height = 0; // If the PPD name is empty then is custom, for some reason PMPaperIsCustom doesn't work here PMPaperGetPPDPaperName(paper, &key); if (PMPaperGetWidth(paper, &width) == noErr && PMPaperGetHeight(paper, &height) == noErr) { - QString ppdKey = key; + QString ppdKey = QString::fromCFString(key); if (ppdKey.isEmpty()) { // Is using a custom page size as defined in the Print Dialog custom settings using mm or inches. // We can't ask PMPaper what those units actually are, we can only get the point size which may return @@ -185,7 +185,7 @@ QT_USE_NAMESPACE pageSize = QPageSize(QSizeF(w / 100.0, h / 100.0), QPageSize::Inch); } } else { - pageSize = QPlatformPrintDevice::createPageSize(key, QSize(width, height), QString()); + pageSize = QPlatformPrintDevice::createPageSize(ppdKey, QSize(width, height), QString()); } } if (pageSize.isValid() && !pageSize.isEquivalentTo(printer->pageLayout().pageSize())) diff --git a/src/printsupport/kernel/qpaintengine_alpha.cpp b/src/printsupport/kernel/qpaintengine_alpha.cpp index 7d4dc18111..ddfa918b90 100644 --- a/src/printsupport/kernel/qpaintengine_alpha.cpp +++ b/src/printsupport/kernel/qpaintengine_alpha.cpp @@ -345,8 +345,8 @@ void QAlphaPaintEngine::flushAndInit(bool init) d->m_picpainter->setFont(painter()->font()); d->m_picpainter->setOpacity(painter()->opacity()); d->m_picpainter->setTransform(painter()->combinedTransform()); - *d->m_picpainter->d_func()->state = *painter()->d_func()->state; d->m_picengine->syncState(); + *d->m_picpainter->d_func()->state = *painter()->d_func()->state; } } diff --git a/src/printsupport/printsupport.pro b/src/printsupport/printsupport.pro index b32ba91c07..6dd3eaab3c 100644 --- a/src/printsupport/printsupport.pro +++ b/src/printsupport/printsupport.pro @@ -1,7 +1,6 @@ TARGET = QtPrintSupport QT = core-private gui-private widgets-private -MODULE_CONFIG = needs_printsupport_plugin DEFINES += QT_NO_USING_NAMESPACE MODULE_PLUGIN_TYPES = \ diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index c052e4c2e7..722595ad52 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -104,6 +104,11 @@ #define QXIDOID 28 #define QCIDOID 29 +#define QBITOID 1560 +#define QVARBITOID 1562 + +#define VARHDRSZ 4 + /* This is a compile time switch - if PQfreemem is declared, the compiler will use that one, otherwise it'll run in this template */ template @@ -533,17 +538,33 @@ QSqlRecord QPSQLResult::record() const f.setName(QString::fromUtf8(PQfname(d->result, i))); else f.setName(QString::fromLocal8Bit(PQfname(d->result, i))); - f.setType(qDecodePSQLType(PQftype(d->result, i))); + int ptype = PQftype(d->result, i); + f.setType(qDecodePSQLType(ptype)); int len = PQfsize(d->result, i); int precision = PQfmod(d->result, i); - // swap length and precision if length == -1 - if (len == -1 && precision > -1) { - len = precision - 4; + + switch (ptype) { + case QNUMERICOID: + if (precision != -1) { + len = (precision >> 16); + precision = ((precision - VARHDRSZ) & 0xffff); + } + break; + case QBITOID: + case QVARBITOID: + len = precision; precision = -1; + break; + default: + if (len == -1 && precision >= VARHDRSZ) { + len = precision - VARHDRSZ; + precision = -1; + } } + f.setLength(len); f.setPrecision(precision); - f.setSqlType(PQftype(d->result, i)); + f.setSqlType(ptype); info.append(f); } return info; diff --git a/src/sql/kernel/qsqlerror.cpp b/src/sql/kernel/qsqlerror.cpp index 1763722e8a..1979e5d1f5 100644 --- a/src/sql/kernel/qsqlerror.cpp +++ b/src/sql/kernel/qsqlerror.cpp @@ -107,7 +107,8 @@ QSqlError::QSqlError(const QString& driverText, const QString& databaseText, Err d->driverError = driverText; d->databaseError = databaseText; d->errorType = type; - d->errorCode = QString::number(number); + if (number != -1) + d->errorCode = QString::number(number); } #endif @@ -287,7 +288,7 @@ void QSqlError::setType(ErrorType type) #if QT_DEPRECATED_SINCE(5, 3) int QSqlError::number() const { - return d->errorCode.toInt(); + return d->errorCode.isEmpty() ? -1 : d->errorCode.toInt(); } #endif diff --git a/src/sql/kernel/qsqlerror.h b/src/sql/kernel/qsqlerror.h index 4e27ab03ae..679e0f9e3c 100644 --- a/src/sql/kernel/qsqlerror.h +++ b/src/sql/kernel/qsqlerror.h @@ -60,15 +60,13 @@ public: UnknownError }; #if QT_DEPRECATED_SINCE(5, 3) - QSqlError( const QString& driverText = QString(), - const QString& databaseText = QString(), - ErrorType type = NoError, - int number = -1); + QT_DEPRECATED QSqlError(const QString &driverText, const QString &databaseText, + ErrorType type, int number); #endif - QSqlError(const QString &driverText, - const QString &databaseText, - ErrorType type, - const QString &errorCode); + QSqlError(const QString &driverText = QString(), + const QString &databaseText = QString(), + ErrorType type = NoError, + const QString &errorCode = QString()); QSqlError(const QSqlError& other); QSqlError& operator=(const QSqlError& other); bool operator==(const QSqlError& other) const; @@ -79,7 +77,7 @@ public: QString databaseText() const; ErrorType type() const; #if QT_DEPRECATED_SINCE(5, 3) - int number() const; + QT_DEPRECATED int number() const; #endif QString nativeErrorCode() const; QString text() const; diff --git a/src/sql/kernel/qsqlquery.cpp b/src/sql/kernel/qsqlquery.cpp index b08f6bc8ef..6b13eb02ed 100644 --- a/src/sql/kernel/qsqlquery.cpp +++ b/src/sql/kernel/qsqlquery.cpp @@ -511,12 +511,23 @@ const QSqlResult* QSqlQuery::result() const \list - \li If the result is currently positioned before the first record or - on the first record, and \a index is negative, there is no change, - and false is returned. + \li If the result is currently positioned before the first record and: + \list + \li \a index is negative or zero, there is no change, and false is + returned. + \li \a index is positive, an attempt is made to position the result + at absolute position \a index - 1, following the sames rule for non + relative seek, above. + \endlist - \li If the result is currently located after the last record, and \a - index is positive, there is no change, and false is returned. + \li If the result is currently positioned after the last record and: + \list + \li \a index is positive or zero, there is no change, and false is + returned. + \li \a index is negative, an attempt is made to position the result + at \a index + 1 relative position from last record, following the + rule below. + \endlist \li If the result is currently located somewhere in the middle, and the relative offset \a index moves the result below zero, the result @@ -549,7 +560,7 @@ bool QSqlQuery::seek(int index, bool relative) switch (at()) { // relative seek case QSql::BeforeFirstRow: if (index > 0) - actualIdx = index; + actualIdx = index - 1; else { return false; } @@ -557,7 +568,7 @@ bool QSqlQuery::seek(int index, bool relative) case QSql::AfterLastRow: if (index < 0) { d->sqlResult->fetchLast(); - actualIdx = at() + index; + actualIdx = at() + index + 1; } else { return false; } diff --git a/src/testlib/doc/src/qttestlib-manual.qdoc b/src/testlib/doc/src/qttestlib-manual.qdoc index 13654972ec..4125e63ddc 100644 --- a/src/testlib/doc/src/qttestlib-manual.qdoc +++ b/src/testlib/doc/src/qttestlib-manual.qdoc @@ -315,12 +315,15 @@ \row \li CPU tick counter \li -tickcounter \li Windows, Mac OS X, Linux, many UNIX-like systems. - \row \li Valgrind Callgrind - \li -callgrind - \li Linux (if installed) \row \li Event Counter \li -eventcounter \li All platforms + \row \li Valgrind Callgrind + \li -callgrind + \li Linux (if installed) + \row \li Linux Perf + \li -perf + \li Linux \endtable In short, walltime is always available but requires many repetitions to @@ -335,6 +338,16 @@ that were received by the event loop before they are sent to their corresponding targets (this might include non-Qt events). + The Linux Performance Monitoring solution is available only on Linux and + provides many different counters, which can be selected by passing an + additional option \c {-perfcounter countername}, such as \c {-perfcounter + cache-misses}, \c {-perfcounter branch-misses}, or \c {-perfcounter + l1d-load-misses}. The default counter is \c {cpu-cycles}. The full list of + counters can be obtained by running any benchmark executable with the + option \c -perfcounterlist. + + Note that using the performance counter may require enabling access to non-privileged applications. + \note Depending on the device configuration, tick counters on the Windows CE platform may not be as fine-grained, compared to other platforms. Devices that do not support high-resolution timers default to diff --git a/src/testlib/qtest_gui.h b/src/testlib/qtest_gui.h index a9ac7777c3..7c68b0fd77 100644 --- a/src/testlib/qtest_gui.h +++ b/src/testlib/qtest_gui.h @@ -98,7 +98,7 @@ inline bool qCompare(QImage const &t1, QImage const &t2, } if (t1Null && t2Null) return compare_helper(true, 0, 0, 0, actual, expected, file, line); - if (t1.width() != t2.width() || t2.height() != t2.height()) { + if (t1.width() != t2.width() || t1.height() != t2.height()) { qsnprintf(msg, 1024, "Compared QImages differ in size.\n" " Actual (%s): %dx%d\n" " Expected (%s): %dx%d", @@ -132,7 +132,7 @@ inline bool qCompare(QPixmap const &t1, QPixmap const &t2, const char *actual, c } if (t1Null && t2Null) return compare_helper(true, 0, 0, 0, actual, expected, file, line); - if (t1.width() != t2.width() || t2.height() != t2.height()) { + if (t1.width() != t2.width() || t1.height() != t2.height()) { qsnprintf(msg, 1024, "Compared QPixmaps differ in size.\n" " Actual (%s): %dx%d\n" " Expected (%s): %dx%d", diff --git a/src/testlib/qtestaccessible.h b/src/testlib/qtestaccessible.h index f27651c3ad..ef6f61bd82 100644 --- a/src/testlib/qtestaccessible.h +++ b/src/testlib/qtestaccessible.h @@ -253,12 +253,10 @@ private: { QString rc; QDebug str = QDebug(&rc).nospace(); - str << "Event " << needle->object() << ", type: " - << needle->type() << ", child: " << needle->child() - << " not found at head of event list of size " << haystack.size() << " :"; + str << "Event " << *needle + << " not found at head of event list of size " << haystack.size() << " :"; Q_FOREACH (const QAccessibleEvent *e, haystack) - str << ' ' << e->object() << ", type: " - << e->type() << ", child: " << e->child(); + str << ' ' << *e; return rc; } diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp index a9abca0ef8..859f6743cd 100644 --- a/src/testlib/qtestresult.cpp +++ b/src/testlib/qtestresult.cpp @@ -51,6 +51,8 @@ #include #include +static const char *currentAppName = 0; + QT_BEGIN_NAMESPACE namespace QTest @@ -64,8 +66,6 @@ namespace QTest static const char *expectFailComment = 0; static int expectFailMode = 0; - - static const char *currentAppName = 0; } void QTestResult::reset() @@ -322,12 +322,12 @@ bool QTestResult::skipCurrentTest() void QTestResult::setCurrentAppName(const char *appName) { - QTest::currentAppName = appName; + ::currentAppName = appName; } const char *QTestResult::currentAppName() { - return QTest::currentAppName; + return ::currentAppName; } QT_END_NAMESPACE diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 3345cf4d64..c63e80f90f 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -985,6 +985,7 @@ void Generator::generateMetacall() fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n", propindex, p.type.constData(), prefix.constData(), p.member.constData()); } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } @@ -1033,6 +1034,7 @@ void Generator::generateMetacall() fprintf(out, " break;\n"); } } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } @@ -1056,6 +1058,7 @@ void Generator::generateMetacall() fprintf(out, " case %d: %s%s; break;\n", propindex, prefix.constData(), p.reset.constData()); } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } fprintf(out, @@ -1074,6 +1077,7 @@ void Generator::generateMetacall() fprintf(out, " case %d: *_b = %s; break;\n", propindex, p.designable.constData()); } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } fprintf(out, @@ -1092,6 +1096,7 @@ void Generator::generateMetacall() fprintf(out, " case %d: *_b = %s; break;\n", propindex, p.scriptable.constData()); } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } fprintf(out, @@ -1110,6 +1115,7 @@ void Generator::generateMetacall() fprintf(out, " case %d: *_b = %s; break;\n", propindex, p.stored.constData()); } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } fprintf(out, @@ -1128,6 +1134,7 @@ void Generator::generateMetacall() fprintf(out, " case %d: *_b = %s; break;\n", propindex, p.editable.constData()); } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } fprintf(out, @@ -1147,6 +1154,7 @@ void Generator::generateMetacall() fprintf(out, " case %d: *_b = %s; break;\n", propindex, p.user.constData()); } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); } fprintf(out, @@ -1228,6 +1236,7 @@ void Generator::generateStaticMetacall() fprintf(out, ");\n"); fprintf(out, " if (_a[0]) *reinterpret_cast(_a[0]) = _r; } break;\n"); } + fprintf(out, " default: break;\n"); fprintf(out, " }\n"); fprintf(out, " }"); needElse = true; diff --git a/src/tools/moc/token.cpp b/src/tools/moc/token.cpp index a936555980..36b413ca84 100644 --- a/src/tools/moc/token.cpp +++ b/src/tools/moc/token.cpp @@ -47,174 +47,9 @@ QT_BEGIN_NAMESPACE const char *tokenTypeName(Token t) { switch (t) { - case NOTOKEN: return "NOTOKEN"; - case IDENTIFIER: return "IDENTIFIER"; - case INTEGER_LITERAL: return "INTEGER_LITERAL"; - case CHARACTER_LITERAL: return "CHARACTER_LITERAL"; - case STRING_LITERAL: return "STRING_LITERAL"; - case BOOLEAN_LITERAL: return "BOOLEAN_LITERAL"; - case HEADER_NAME: return "HEADER_NAME"; - case LANGLE: return "LANGLE"; - case RANGLE: return "RANGLE"; - case LPAREN: return "LPAREN"; - case RPAREN: return "RPAREN"; - case ELIPSIS: return "ELIPSIS"; - case LBRACK: return "LBRACK"; - case RBRACK: return "RBRACK"; - case LBRACE: return "LBRACE"; - case RBRACE: return "RBRACE"; - case EQ: return "EQ"; - case SCOPE: return "SCOPE"; - case SEMIC: return "SEMIC"; - case COLON: return "COLON"; - case DOTSTAR: return "DOTSTAR"; - case QUESTION: return "QUESTION"; - case DOT: return "DOT"; - case DYNAMIC_CAST: return "DYNAMIC_CAST"; - case STATIC_CAST: return "STATIC_CAST"; - case REINTERPRET_CAST: return "REINTERPRET_CAST"; - case CONST_CAST: return "CONST_CAST"; - case TYPEID: return "TYPEID"; - case THIS: return "THIS"; - case TEMPLATE: return "TEMPLATE"; - case THROW: return "THROW"; - case TRY: return "TRY"; - case CATCH: return "CATCH"; - case TYPEDEF: return "TYPEDEF"; - case FRIEND: return "FRIEND"; - case CLASS: return "CLASS"; - case NAMESPACE: return "NAMESPACE"; - case ENUM: return "ENUM"; - case STRUCT: return "STRUCT"; - case UNION: return "UNION"; - case VIRTUAL: return "VIRTUAL"; - case PRIVATE: return "PRIVATE"; - case PROTECTED: return "PROTECTED"; - case PUBLIC: return "PUBLIC"; - case EXPORT: return "EXPORT"; - case AUTO: return "AUTO"; - case REGISTER: return "REGISTER"; - case EXTERN: return "EXTERN"; - case MUTABLE: return "MUTABLE"; - case ASM: return "ASM"; - case USING: return "USING"; - case INLINE: return "INLINE"; - case EXPLICIT: return "EXPLICIT"; - case STATIC: return "STATIC"; - case CONST: return "CONST"; - case VOLATILE: return "VOLATILE"; - case OPERATOR: return "OPERATOR"; - case SIZEOF: return "SIZEOF"; - case NEW: return "NEW"; - case DELETE: return "DELETE"; - case PLUS: return "PLUS"; - case MINUS: return "MINUS"; - case STAR: return "STAR"; - case SLASH: return "SLASH"; - case PERCENT: return "PERCENT"; - case HAT: return "HAT"; - case AND: return "AND"; - case OR: return "OR"; - case TILDE: return "TILDE"; - case NOT: return "NOT"; - case PLUS_EQ: return "PLUS_EQ"; - case MINUS_EQ: return "MINUS_EQ"; - case STAR_EQ: return "STAR_EQ"; - case SLASH_EQ: return "SLASH_EQ"; - case PERCENT_EQ: return "PERCENT_EQ"; - case HAT_EQ: return "HAT_EQ"; - case AND_EQ: return "AND_EQ"; - case OR_EQ: return "OR_EQ"; - case LTLT: return "LTLT"; - case GTGT: return "GTGT"; - case GTGT_EQ: return "GTGT_EQ"; - case LTLT_EQ: return "LTLT_EQ"; - case EQEQ: return "EQEQ"; - case NE: return "NE"; - case LE: return "LE"; - case GE: return "GE"; - case ANDAND: return "ANDAND"; - case OROR: return "OROR"; - case INCR: return "INCR"; - case DECR: return "DECR"; - case COMMA: return "COMMA"; - case ARROW_STAR: return "ARROW_STAR"; - case ARROW: return "ARROW"; - case CHAR: return "CHAR"; - case WCHAR: return "WCHAR"; - case BOOL: return "BOOL"; - case SHORT: return "SHORT"; - case INT: return "INT"; - case LONG: return "LONG"; - case SIGNED: return "SIGNED"; - case UNSIGNED: return "UNSIGNED"; - case FLOAT: return "FLOAT"; - case DOUBLE: return "DOUBLE"; - case VOID: return "VOID"; - case CASE: return "CASE"; - case DEFAULT: return "DEFAULT"; - case IF: return "IF"; - case ELSE: return "ELSE"; - case SWITCH: return "SWITCH"; - case WHILE: return "WHILE"; - case DO: return "DO"; - case FOR: return "FOR"; - case BREAK: return "BREAK"; - case CONTINUE: return "CONTINUE"; - case GOTO: return "GOTO"; - case SIGNALS: return "SIGNALS"; - case SLOTS: return "SLOTS"; - case RETURN: return "RETURN"; - case Q_OBJECT_TOKEN: return "Q_OBJECT_TOKEN"; - case Q_GADGET_TOKEN: return "Q_GADGET_TOKEN"; - case Q_PROPERTY_TOKEN: return "Q_PROPERTY_TOKEN"; - case Q_ENUMS_TOKEN: return "Q_ENUMS_TOKEN"; - case Q_FLAGS_TOKEN: return "Q_FLAGS_TOKEN"; - case Q_DECLARE_FLAGS_TOKEN: return "Q_DECLARE_FLAGS_TOKEN"; - case Q_DECLARE_INTERFACE_TOKEN: return "Q_DECLARE_INTERFACE_TOKEN"; - case Q_CLASSINFO_TOKEN: return "Q_CLASSINFO_TOKEN"; - case Q_INTERFACES_TOKEN: return "Q_INTERFACES_TOKEN"; - case Q_SIGNALS_TOKEN: return "Q_SIGNALS_TOKEN"; - case Q_SLOTS_TOKEN: return "Q_SLOTS_TOKEN"; - case Q_SIGNAL_TOKEN: return "Q_SIGNAL_TOKEN"; - case Q_SLOT_TOKEN: return "Q_SLOT_TOKEN"; - case Q_PRIVATE_SLOT_TOKEN: return "Q_PRIVATE_SLOT_TOKEN"; - case Q_PRIVATE_PROPERTY_TOKEN: return "Q_PRIVATE_PROPERTY_TOKEN"; - case Q_REVISION_TOKEN: return "Q_REVISION_TOKEN"; - case SPECIAL_TREATMENT_MARK: return "SPECIAL_TREATMENT_MARK"; - case MOC_INCLUDE_BEGIN: return "MOC_INCLUDE_BEGIN"; - case MOC_INCLUDE_END: return "MOC_INCLUDE_END"; - case CPP_COMMENT: return "CPP_COMMENT"; - case C_COMMENT: return "C_COMMENT"; - case FLOATING_LITERAL: return "FLOATING_LITERAL"; - case HASH: return "HASH"; - case QUOTE: return "QUOTE"; - case SINGLEQUOTE: return "SINGLEQUOTE"; - case DIGIT: return "DIGIT"; - case CHARACTER: return "CHARACTER"; - case NEWLINE: return "NEWLINE"; - case WHITESPACE: return "WHITESPACE"; - case BACKSLASH: return "BACKSLASH"; - case INCOMPLETE: return "INCOMPLETE"; - case PP_DEFINE: return "PP_DEFINE"; - case PP_UNDEF: return "PP_UNDEF"; - case PP_IF: return "PP_IF"; - case PP_IFDEF: return "PP_IFDEF"; - case PP_IFNDEF: return "PP_IFNDEF"; - case PP_ELIF: return "PP_ELIF"; - case PP_ELSE: return "PP_ELSE"; - case PP_ENDIF: return "PP_ENDIF"; - case PP_INCLUDE: return "PP_INCLUDE"; - case PP_HASHHASH: return "PP_HASHHASH"; - case PP_HASH: return "PP_HASH"; - case PP_DEFINED: return "PP_DEFINED"; - case PP_INCOMPLETE: return "PP_INCOMPLETE"; - case PP_MOC_TRUE: return "PP_MOC_TRUE"; - case PP_MOC_FALSE: return "PP_MOC_FALSE"; - case Q_DECLARE_METATYPE_TOKEN: return "Q_DECLARE_METATYPE_TOKEN"; - case Q_MOC_COMPAT_TOKEN: return "Q_MOC_COMPAT_TOKEN"; - case Q_INVOKABLE_TOKEN: return "Q_INVOKABLE_TOKEN"; - case Q_SCRIPTABLE_TOKEN: return "Q_SCRIPTABLE_TOKEN"; +#define CREATE_CASE(Name) case Name: return #Name; + FOR_ALL_TOKENS(CREATE_CASE) +#undef CREATE_CASE } return ""; } diff --git a/src/tools/moc/token.h b/src/tools/moc/token.h index 378d4c63f7..2920fadbb9 100644 --- a/src/tools/moc/token.h +++ b/src/tools/moc/token.h @@ -46,222 +46,228 @@ QT_BEGIN_NAMESPACE +#define FOR_ALL_TOKENS(F) \ + F(NOTOKEN) \ + F(IDENTIFIER) \ + F(INTEGER_LITERAL) \ + F(CHARACTER_LITERAL) \ + F(STRING_LITERAL) \ + F(BOOLEAN_LITERAL) \ + F(HEADER_NAME) \ + F(LANGLE) \ + F(RANGLE) \ + F(LPAREN) \ + F(RPAREN) \ + F(ELIPSIS) \ + F(LBRACK) \ + F(RBRACK) \ + F(LBRACE) \ + F(RBRACE) \ + F(EQ) \ + F(SCOPE) \ + F(SEMIC) \ + F(COLON) \ + F(DOTSTAR) \ + F(QUESTION) \ + F(DOT) \ + F(DYNAMIC_CAST) \ + F(STATIC_CAST) \ + F(REINTERPRET_CAST) \ + F(CONST_CAST) \ + F(TYPEID) \ + F(THIS) \ + F(TEMPLATE) \ + F(THROW) \ + F(TRY) \ + F(CATCH) \ + F(TYPEDEF) \ + F(FRIEND) \ + F(CLASS) \ + F(NAMESPACE) \ + F(ENUM) \ + F(STRUCT) \ + F(UNION) \ + F(VIRTUAL) \ + F(PRIVATE) \ + F(PROTECTED) \ + F(PUBLIC) \ + F(EXPORT) \ + F(AUTO) \ + F(REGISTER) \ + F(EXTERN) \ + F(MUTABLE) \ + F(ASM) \ + F(USING) \ + F(INLINE) \ + F(EXPLICIT) \ + F(STATIC) \ + F(CONST) \ + F(VOLATILE) \ + F(OPERATOR) \ + F(SIZEOF) \ + F(NEW) \ + F(DELETE) \ + F(PLUS) \ + F(MINUS) \ + F(STAR) \ + F(SLASH) \ + F(PERCENT) \ + F(HAT) \ + F(AND) \ + F(OR) \ + F(TILDE) \ + F(NOT) \ + F(PLUS_EQ) \ + F(MINUS_EQ) \ + F(STAR_EQ) \ + F(SLASH_EQ) \ + F(PERCENT_EQ) \ + F(HAT_EQ) \ + F(AND_EQ) \ + F(OR_EQ) \ + F(LTLT) \ + F(GTGT) \ + F(GTGT_EQ) \ + F(LTLT_EQ) \ + F(EQEQ) \ + F(NE) \ + F(LE) \ + F(GE) \ + F(ANDAND) \ + F(OROR) \ + F(INCR) \ + F(DECR) \ + F(COMMA) \ + F(ARROW_STAR) \ + F(ARROW) \ + F(CHAR) \ + F(WCHAR) \ + F(BOOL) \ + F(SHORT) \ + F(INT) \ + F(LONG) \ + F(SIGNED) \ + F(UNSIGNED) \ + F(FLOAT) \ + F(DOUBLE) \ + F(VOID) \ + F(CASE) \ + F(DEFAULT) \ + F(IF) \ + F(ELSE) \ + F(SWITCH) \ + F(WHILE) \ + F(DO) \ + F(FOR) \ + F(BREAK) \ + F(CONTINUE) \ + F(GOTO) \ + F(SIGNALS) \ + F(SLOTS) \ + F(RETURN) \ + F(Q_OBJECT_TOKEN) \ + F(Q_GADGET_TOKEN) \ + F(Q_PROPERTY_TOKEN) \ + F(Q_PLUGIN_METADATA_TOKEN) \ + F(Q_ENUMS_TOKEN) \ + F(Q_FLAGS_TOKEN) \ + F(Q_DECLARE_FLAGS_TOKEN) \ + F(Q_DECLARE_INTERFACE_TOKEN) \ + F(Q_DECLARE_METATYPE_TOKEN) \ + F(Q_CLASSINFO_TOKEN) \ + F(Q_INTERFACES_TOKEN) \ + F(Q_SIGNALS_TOKEN) \ + F(Q_SLOTS_TOKEN) \ + F(Q_SIGNAL_TOKEN) \ + F(Q_SLOT_TOKEN) \ + F(Q_PRIVATE_SLOT_TOKEN) \ + F(Q_MOC_COMPAT_TOKEN) \ + F(Q_INVOKABLE_TOKEN) \ + F(Q_SCRIPTABLE_TOKEN) \ + F(Q_PRIVATE_PROPERTY_TOKEN) \ + F(Q_REVISION_TOKEN) \ + F(SPECIAL_TREATMENT_MARK) \ + F(MOC_INCLUDE_BEGIN) \ + F(MOC_INCLUDE_END) \ + F(CPP_COMMENT) \ + F(C_COMMENT) \ + F(FLOATING_LITERAL) \ + F(HASH) \ + F(QUOTE) \ + F(SINGLEQUOTE) \ + F(LANGLE_SCOPE) \ + F(DIGIT) \ + F(CHARACTER) \ + F(NEWLINE) \ + F(WHITESPACE) \ + F(BACKSLASH) \ + F(INCOMPLETE) \ + F(PP_DEFINE) \ + F(PP_UNDEF) \ + F(PP_IF) \ + F(PP_IFDEF) \ + F(PP_IFNDEF) \ + F(PP_ELIF) \ + F(PP_ELSE) \ + F(PP_ENDIF) \ + F(PP_INCLUDE) \ + F(PP_HASHHASH) \ + F(PP_HASH) \ + F(PP_DEFINED) \ + F(PP_INCOMPLETE) \ + F(PP_MOC_TRUE) \ + F(PP_MOC_FALSE) + + enum Token { - NOTOKEN, - IDENTIFIER, - INTEGER_LITERAL, - CHARACTER_LITERAL, - STRING_LITERAL, - BOOLEAN_LITERAL, - HEADER_NAME, - LANGLE, - RANGLE, - LPAREN, - RPAREN, - ELIPSIS, - LBRACK, - RBRACK, - LBRACE, - RBRACE, - EQ, - SCOPE, - SEMIC, - COLON, - DOTSTAR, - QUESTION, - DOT, - DYNAMIC_CAST, - STATIC_CAST, - REINTERPRET_CAST, - CONST_CAST, - TYPEID, - THIS, - TEMPLATE, - THROW, - TRY, - CATCH, - TYPEDEF, - FRIEND, - CLASS, - NAMESPACE, - ENUM, - STRUCT, - UNION, - VIRTUAL, - PRIVATE, - PROTECTED, - PUBLIC, - EXPORT, - AUTO, - REGISTER, - EXTERN, - MUTABLE, - ASM, - USING, - INLINE, - EXPLICIT, - STATIC, - CONST, - VOLATILE, - OPERATOR, - SIZEOF, - NEW, - DELETE, - PLUS, - MINUS, - STAR, - SLASH, - PERCENT, - HAT, - AND, - OR, - TILDE, - NOT, - PLUS_EQ, - MINUS_EQ, - STAR_EQ, - SLASH_EQ, - PERCENT_EQ, - HAT_EQ, - AND_EQ, - OR_EQ, - LTLT, - GTGT, - GTGT_EQ, - LTLT_EQ, - EQEQ, - NE, - LE, - GE, - ANDAND, - OROR, - INCR, - DECR, - COMMA, - ARROW_STAR, - ARROW, - CHAR, - WCHAR, - BOOL, - SHORT, - INT, - LONG, - SIGNED, - UNSIGNED, - FLOAT, - DOUBLE, - VOID, - CASE, - DEFAULT, - IF, - ELSE, - SWITCH, - WHILE, - DO, - FOR, - BREAK, - CONTINUE, - GOTO, - SIGNALS, - SLOTS, - RETURN, - Q_META_TOKEN_BEGIN, - Q_OBJECT_TOKEN = Q_META_TOKEN_BEGIN, - Q_GADGET_TOKEN, - Q_PROPERTY_TOKEN, - Q_PLUGIN_METADATA_TOKEN, - Q_ENUMS_TOKEN, - Q_FLAGS_TOKEN, - Q_DECLARE_FLAGS_TOKEN, - Q_DECLARE_INTERFACE_TOKEN, - Q_DECLARE_METATYPE_TOKEN, - Q_CLASSINFO_TOKEN, - Q_INTERFACES_TOKEN, - Q_SIGNALS_TOKEN, - Q_SLOTS_TOKEN, - Q_SIGNAL_TOKEN, - Q_SLOT_TOKEN, - Q_PRIVATE_SLOT_TOKEN, - Q_MOC_COMPAT_TOKEN, - Q_INVOKABLE_TOKEN, - Q_SCRIPTABLE_TOKEN, - Q_PRIVATE_PROPERTY_TOKEN, - Q_REVISION_TOKEN, - Q_META_TOKEN_END, - SPECIAL_TREATMENT_MARK = Q_META_TOKEN_END, - MOC_INCLUDE_BEGIN, - MOC_INCLUDE_END, - CPP_COMMENT, - C_COMMENT, - FLOATING_LITERAL, - HASH, - QUOTE, - SINGLEQUOTE, - LANGLE_SCOPE, - DIGIT, - CHARACTER, - NEWLINE, - WHITESPACE, - BACKSLASH, - INCOMPLETE, - PP_DEFINE, - PP_UNDEF, - PP_IF, - PP_IFDEF, - PP_IFNDEF, - PP_ELIF, - PP_ELSE, - PP_ENDIF, - PP_INCLUDE, - PP_HASHHASH, - PP_HASH, - PP_DEFINED, - PP_INCOMPLETE, +#define CREATE_ENUM_VALUE(Name) Name, + FOR_ALL_TOKENS(CREATE_ENUM_VALUE) +#undef CREATE_ENUM_VALUE - PP_MOC_TRUE, - PP_MOC_FALSE, - - PP_NOTOKEN = NOTOKEN, - PP_IDENTIFIER = IDENTIFIER, - PP_INTEGER_LITERAL = INTEGER_LITERAL, - PP_CHARACTER_LITERAL = CHARACTER_LITERAL, - PP_STRING_LITERAL = STRING_LITERAL, - PP_LANGLE = LANGLE, - PP_RANGLE = RANGLE, - PP_LPAREN = LPAREN, - PP_RPAREN = RPAREN, - PP_COMMA = COMMA, - PP_PLUS = PLUS, - PP_MINUS = MINUS, - PP_STAR = STAR, - PP_SLASH = SLASH, - PP_PERCENT = PERCENT, - PP_HAT = HAT, + // aliases PP_AND = AND, - PP_OR = OR, - PP_TILDE = TILDE, - PP_NOT = NOT, - PP_LTLT = LTLT, - PP_GTGT = GTGT, - PP_EQEQ = EQEQ, - PP_NE = NE, - PP_LE = LE, - PP_GE = GE, PP_ANDAND = ANDAND, - PP_OROR = OROR, - PP_QUESTION = QUESTION, - PP_COLON = COLON, - PP_FLOATING_LITERAL = FLOATING_LITERAL, - PP_QUOTE = QUOTE, - PP_SINGLEQUOTE = SINGLEQUOTE, - PP_DIGIT = DIGIT, + PP_BACKSLASH = BACKSLASH, PP_CHARACTER = CHARACTER, - PP_WHITESPACE = WHITESPACE, - PP_NEWLINE = NEWLINE, + PP_CHARACTER_LITERAL = CHARACTER_LITERAL, + PP_COLON = COLON, + PP_COMMA = COMMA, PP_CPP_COMMENT = CPP_COMMENT, PP_C_COMMENT = C_COMMENT, - PP_BACKSLASH = BACKSLASH + PP_DIGIT = DIGIT, + PP_EQEQ = EQEQ, + PP_FLOATING_LITERAL = FLOATING_LITERAL, + PP_GE = GE, + PP_GTGT = GTGT, + PP_HAT = HAT, + PP_IDENTIFIER = IDENTIFIER, + PP_INTEGER_LITERAL = INTEGER_LITERAL, + PP_LANGLE = LANGLE, + PP_LE = LE, + PP_LPAREN = LPAREN, + PP_LTLT = LTLT, + PP_MINUS = MINUS, + PP_NE = NE, + PP_NEWLINE = NEWLINE, + PP_NOTOKEN = NOTOKEN, + PP_NOT = NOT, + PP_OR = OR, + PP_OROR = OROR, + PP_PERCENT = PERCENT, + PP_PLUS = PLUS, + PP_QUESTION = QUESTION, + PP_QUOTE = QUOTE, + PP_RANGLE = RANGLE, + PP_RPAREN = RPAREN, + PP_SINGLEQUOTE = SINGLEQUOTE, + PP_SLASH = SLASH, + PP_STAR = STAR, + PP_STRING_LITERAL = STRING_LITERAL, + PP_TILDE = TILDE, + PP_WHITESPACE = WHITESPACE, + Q_META_TOKEN_BEGIN = Q_OBJECT_TOKEN, + Q_META_TOKEN_END = SPECIAL_TREATMENT_MARK }; // for debugging only diff --git a/src/widgets/Qt5WidgetsConfigExtras.cmake.in b/src/widgets/Qt5WidgetsConfigExtras.cmake.in index e5650ff362..99d87e2e46 100644 --- a/src/widgets/Qt5WidgetsConfigExtras.cmake.in +++ b/src/widgets/Qt5WidgetsConfigExtras.cmake.in @@ -14,4 +14,6 @@ if (NOT TARGET Qt5::uic) ) endif() +include(\"${CMAKE_CURRENT_LIST_DIR}/Qt5Widgets_AccessibleFactory.cmake\" OPTIONAL) + set(Qt5Widgets_UIC_EXECUTABLE Qt5::uic) diff --git a/src/widgets/accessible/complexwidgets.cpp b/src/widgets/accessible/complexwidgets.cpp index 5d76ecafbc..9bf2a00d57 100644 --- a/src/widgets/accessible/complexwidgets.cpp +++ b/src/widgets/accessible/complexwidgets.cpp @@ -315,19 +315,19 @@ QString QAccessibleComboBox::text(QAccessible::Text t) const QStringList QAccessibleComboBox::actionNames() const { - return QStringList(showMenuAction()); + return QStringList() << showMenuAction() << pressAction(); } QString QAccessibleComboBox::localizedActionDescription(const QString &actionName) const { - if (actionName == showMenuAction()) + if (actionName == showMenuAction() || actionName == pressAction()) return QComboBox::tr("Open the combo box selection popup"); return QString(); } void QAccessibleComboBox::doAction(const QString &actionName) { - if (actionName == showMenuAction()) { + if (actionName == showMenuAction() || actionName == pressAction()) { if (comboBox()->view()->isVisible()) { comboBox()->hidePopup(); } else { diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 80e8d152ff..bb8cdec896 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWidgets module of the Qt Toolkit. @@ -71,6 +71,7 @@ extern bool qt_priv_ptr_valid; #endif #if defined(Q_OS_UNIX) #include +#include // for pathconf() on OS X #elif defined(Q_OS_WIN) # include #endif @@ -1018,6 +1019,44 @@ QUrl QFileDialog::directoryUrl() const return QUrl::fromLocalFile(directory().absolutePath()); } +// FIXME Qt 5.4: Use upcoming QVolumeInfo class to determine this information? +static inline bool isCaseSensitiveFileSystem(const QString &path) +{ + Q_UNUSED(path) +#if defined(Q_OS_WIN) + // Return case insensitive unconditionally, even if someone has a case sensitive + // file system mounted, wrongly capitalized drive letters will cause mismatches. + return false; +#elif defined(Q_OS_OSX) + return pathconf(QFile::encodeName(path).constData(), _PC_CASE_SENSITIVE); +#else + return true; +#endif +} + +// Determine the file name to be set on the line edit from the path +// passed to selectFile() in mode QFileDialog::AcceptSave. +static inline QString fileFromPath(const QString &rootPath, QString path) +{ + if (!QFileInfo(path).isAbsolute()) + return path; + if (path.startsWith(rootPath, isCaseSensitiveFileSystem(rootPath) ? Qt::CaseSensitive : Qt::CaseInsensitive)) + path.remove(0, rootPath.size()); + + if (path.isEmpty()) + return path; + + if (path.at(0) == QDir::separator() +#ifdef Q_OS_WIN + //On Windows both cases can happen + || path.at(0) == QLatin1Char('/') +#endif + ) { + path.remove(0, 1); + } + return path; +} + /*! Selects the given \a filename in the file dialog. @@ -1049,28 +1088,9 @@ void QFileDialog::selectFile(const QString &filename) } QModelIndex index = d->model->index(filename); - QString file; - if (!index.isValid()) { - // save as dialog where we want to input a default value - QString text = filename; - if (QFileInfo(filename).isAbsolute()) { - QString current = d->rootPath(); - text.remove(current); - if (text.at(0) == QDir::separator() -#ifdef Q_OS_WIN - //On Windows both cases can happen - || text.at(0) == QLatin1Char('/') -#endif - ) - text = text.remove(0,1); - } - file = text; - } else { - file = index.data().toString(); - } d->qFileDialogUi->listView->selectionModel()->clear(); if (!isVisible() || !d->lineEdit()->hasFocus()) - d->lineEdit()->setText(file); + d->lineEdit()->setText(index.isValid() ? index.data().toString() : fileFromPath(d->rootPath(), filename)); } /*! @@ -1255,7 +1275,7 @@ QStringList QFileDialog::selectedFiles() const QStringList files; foreach (const QUrl &file, d->userSelectedFiles()) files.append(file.toLocalFile()); - if (files.isEmpty()) { + if (files.isEmpty() && d->usingWidgets()) { const FileMode fm = fileMode(); if (fm != ExistingFile && fm != ExistingFiles) files.append(d->rootIndex().data(QFileSystemModel::FilePathRole).toString()); @@ -1600,7 +1620,7 @@ QFileDialog::ViewMode QFileDialog::viewMode() const { Q_D(const QFileDialog); if (!d->usingWidgets()) - return QFileDialog::List; + return static_cast(d->options->viewMode()); return (d->qFileDialogUi->stackedWidget->currentWidget() == d->qFileDialogUi->listView->parent() ? QFileDialog::List : QFileDialog::Detail); } diff --git a/src/widgets/graphicsview/qgraphicsproxywidget.cpp b/src/widgets/graphicsview/qgraphicsproxywidget.cpp index 68944817f6..f5db85b698 100644 --- a/src/widgets/graphicsview/qgraphicsproxywidget.cpp +++ b/src/widgets/graphicsview/qgraphicsproxywidget.cpp @@ -379,6 +379,10 @@ QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next) void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot() { Q_Q(QGraphicsProxyWidget); + if (!widget.isNull()) { + if (QWExtra *extra = widget->d_func()->extra) + extra->proxyWidget = 0; + } widget = 0; delete q; } diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 8d0a51606e..9c2c2bab16 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -336,6 +336,15 @@ QApplicationPrivate::~QApplicationPrivate() See setColorSpec() for full details. */ +/*! + \fn QApplication::setGraphicsSystem(const QString &) + \obsolete + + This call has no effect. + + Use the QPA framework instead. +*/ + /*! \fn QWidget *QApplication::topLevelAt(const QPoint &point) @@ -360,6 +369,7 @@ QApplicationPrivate::~QApplicationPrivate() void qt_init(QApplicationPrivate *priv, int type ); +void qt_init_tooltip_palette(); void qt_cleanup(); QStyle *QApplicationPrivate::app_style = 0; // default application style @@ -4022,6 +4032,7 @@ void QApplicationPrivate::notifyThemeChanged() QGuiApplicationPrivate::notifyThemeChanged(); clearSystemPalette(); initSystemPalette(); + qt_init_tooltip_palette(); } #ifndef QT_NO_DRAGANDDROP diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp index ccd6c2b03c..1c6bcfa9ce 100644 --- a/src/widgets/kernel/qapplication_qpa.cpp +++ b/src/widgets/kernel/qapplication_qpa.cpp @@ -447,6 +447,14 @@ void QApplication::alert(QWidget *widget, int duration) } } +void qt_init_tooltip_palette() +{ +#ifndef QT_NO_TOOLTIP + if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette)) + QToolTip::setPalette(*toolTipPalette); +#endif +} + void qt_init(QApplicationPrivate *priv, int type) { Q_UNUSED(priv); @@ -454,10 +462,7 @@ void qt_init(QApplicationPrivate *priv, int type) QColormap::initialize(); -#ifndef QT_NO_TOOLTIP - if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette)) - QToolTip::setPalette(*toolTipPalette); -#endif + qt_init_tooltip_palette(); QApplicationPrivate::initializeWidgetFontHash(); } diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp index 5aea55e196..2b43fd7f6d 100644 --- a/src/widgets/kernel/qtooltip.cpp +++ b/src/widgets/kernel/qtooltip.cpp @@ -512,9 +512,9 @@ void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, cons else if (QApplication::isEffectEnabled(Qt::UI_AnimateTooltip)) qScrollEffect(QTipLabel::instance); else - QTipLabel::instance->show(); + QTipLabel::instance->showNormal(); #else - QTipLabel::instance->show(); + QTipLabel::instance->showNormal(); #endif } } diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 926db7febf..016abfa0dc 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -6006,10 +6006,8 @@ void QWidget::setFocus(Qt::FocusReason reason) if (!(testAttribute(Qt::WA_WState_Created) && window()->windowType() != Qt::Popup && internalWinId())) //setFocusWidget will already post a focus event for us (that the AT client receives) on Windows # endif -# ifdef Q_OS_UNIX // menus update the focus manually and this would create bogus events if (!(f->inherits("QMenuBar") || f->inherits("QMenu") || f->inherits("QMenuItem"))) -# endif { QAccessibleEvent event(f, QAccessible::Focus); QAccessible::updateAccessibility(&event); @@ -8530,6 +8528,8 @@ void QWidget::mouseReleaseEvent(QMouseEvent *event) This event handler, for event \a event, can be reimplemented in a subclass to receive mouse double click events for the widget. + The default implementation calls mousePressEvent(). + \note The widget will also receive mouse press and mouse release events in addition to the double click event. It is up to the developer to ensure that the application interprets these events @@ -8541,7 +8541,7 @@ void QWidget::mouseReleaseEvent(QMouseEvent *event) void QWidget::mouseDoubleClickEvent(QMouseEvent *event) { - event->ignore(); + mousePressEvent(event); } #ifndef QT_NO_WHEELEVENT diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp index 4618e1c91d..1770e60c2e 100644 --- a/src/widgets/kernel/qwindowcontainer.cpp +++ b/src/widgets/kernel/qwindowcontainer.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWidgets module of the Qt Toolkit. @@ -72,7 +72,14 @@ public: void updateGeometry() { Q_Q(QWindowContainer); - if (usesNativeWidgets) + if (q->geometry().bottom() <= 0 || q->geometry().right() <= 0) + /* Qt (e.g. QSplitter) sometimes prefer to hide a widget by *not* calling + setVisible(false). This is often done by setting its coordinates to a sufficiently + negative value so that its clipped outside the parent. Since a QWindow is not clipped + to widgets in general, it needs to be dealt with as a special case. + */ + window->setGeometry(q->geometry()); + else if (usesNativeWidgets) window->setGeometry(q->rect()); else window->setGeometry(QRect(q->mapTo(q->window(), QPoint()), q->size())); diff --git a/src/widgets/styles/qgtkstyle_p.cpp b/src/widgets/styles/qgtkstyle_p.cpp index 2bd978bcb8..2c64225c70 100644 --- a/src/widgets/styles/qgtkstyle_p.cpp +++ b/src/widgets/styles/qgtkstyle_p.cpp @@ -855,7 +855,7 @@ QFont QGtkStylePrivate::getThemeFont() QIcon QGtkStylePrivate::getFilesystemIcon(const QFileInfo &info) { QIcon icon; - if (gnome_vfs_init && gnome_icon_lookup_sync) { + if (isThemeAvailable() && gnome_vfs_init && gnome_icon_lookup_sync) { gnome_vfs_init(); GtkIconTheme *theme = gtk_icon_theme_get_default(); QByteArray fileurl = QUrl::fromLocalFile(info.absoluteFilePath()).toEncoded(); diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 886491a440..f3bbe11563 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1326,12 +1326,30 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem // an extra check here before using the mini and small buttons. int h = combo->rect.size().height(); if (combo->editable){ - if (h < 21) - bdi->kind = kThemeComboBoxMini; - else if (h < 26) - bdi->kind = kThemeComboBoxSmall; - else - bdi->kind = kThemeComboBox; + if (qobject_cast(widget)) { + // Except when, you know, we get a QDateTimeEdit with calendarPopup + // enabled. And then things get weird, basically because it's a + // transvestite spinbox with editable combobox tendencies. Meaning + // that it wants to look a combobox, except that it isn't one, so it + // doesn't get all those extra free margins around. (Don't know whose + // idea those margins were, but now it looks like we're stuck with + // them forever). So anyway, the height threshold should be smaller + // in this case, or the style gets confused when it needs to render + // or return any subcontrol size of the poor thing. + if (h < 9) + bdi->kind = kThemeComboBoxMini; + else if (h < 22) + bdi->kind = kThemeComboBoxSmall; + else + bdi->kind = kThemeComboBox; + } else { + if (h < 21) + bdi->kind = kThemeComboBoxMini; + else if (h < 26) + bdi->kind = kThemeComboBoxSmall; + else + bdi->kind = kThemeComboBox; + } } else { // Even if we specify that we want the kThemePopupButton, Carbon // will use the kThemePopupButtonSmall if the size matches. So we diff --git a/src/widgets/widgets/qfontcombobox.cpp b/src/widgets/widgets/qfontcombobox.cpp index 2bbf3730db..40ca73904c 100644 --- a/src/widgets/widgets/qfontcombobox.cpp +++ b/src/widgets/widgets/qfontcombobox.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -546,8 +547,10 @@ bool QFontComboBox::event(QEvent *e) { if (e->type() == QEvent::Resize) { QListView *lview = qobject_cast(view()); - if (lview) - lview->window()->setFixedWidth(width() * 5 / 3); + if (lview) { + setFixedWidth(qMin(width() * 5 / 3, + QApplication::desktop()->availableGeometry(lview).width())); + } } return QComboBox::event(e); } diff --git a/src/widgets/widgets/qmacnativewidget_mac.mm b/src/widgets/widgets/qmacnativewidget_mac.mm index 66a1ed7ce7..d3f3515b04 100644 --- a/src/widgets/widgets/qmacnativewidget_mac.mm +++ b/src/widgets/widgets/qmacnativewidget_mac.mm @@ -128,6 +128,7 @@ QMacNativeWidget::QMacNativeWidget(NSView *parentView) setAttribute(Qt::WA_SetPalette, false); setAttribute(Qt::WA_LayoutUsesWidgetRect); setAttribute(Qt::WA_TranslucentBackground); + setAttribute(Qt::WA_NoSystemBackground, false); } /*! diff --git a/src/widgets/widgets/qmdisubwindow.cpp b/src/widgets/widgets/qmdisubwindow.cpp index b1adb3f760..9104074122 100644 --- a/src/widgets/widgets/qmdisubwindow.cpp +++ b/src/widgets/widgets/qmdisubwindow.cpp @@ -1676,15 +1676,18 @@ void QMdiSubWindowPrivate::ensureWindowState(Qt::WindowState state) switch (state) { case Qt::WindowMinimized: windowStates &= ~Qt::WindowMaximized; + windowStates &= ~Qt::WindowFullScreen; windowStates &= ~Qt::WindowNoState; break; case Qt::WindowMaximized: windowStates &= ~Qt::WindowMinimized; + windowStates &= ~Qt::WindowFullScreen; windowStates &= ~Qt::WindowNoState; break; case Qt::WindowNoState: windowStates &= ~Qt::WindowMinimized; windowStates &= ~Qt::WindowMaximized; + windowStates &= ~Qt::WindowFullScreen; break; default: break; @@ -2732,7 +2735,7 @@ bool QMdiSubWindow::eventFilter(QObject *object, QEvent *event) showMinimized(); else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) showMaximized(); - else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized))) + else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized | Qt::WindowFullScreen))) showNormal(); break; } @@ -3005,7 +3008,7 @@ void QMdiSubWindow::changeEvent(QEvent *changeEvent) d->setMinimizeMode(); else if (!(oldState & Qt::WindowMaximized) && (newState & Qt::WindowMaximized)) d->setMaximizeMode(); - else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized))) + else if (!(newState & (Qt::WindowMaximized | Qt::WindowMinimized | Qt::WindowFullScreen))) d->setNormalMode(); if (d->isActive) diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index eb93e461c0..403ebe7f49 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -50,6 +50,9 @@ #include "qlayout.h" #include "qpainter.h" #include +#ifdef Q_OS_OSX +#include "qmacnativewidget_mac.h" +#endif #include "qapplication.h" #include "qdesktopwidget.h" #ifndef QT_NO_ACCESSIBILITY @@ -163,7 +166,7 @@ void QMenuPrivate::setPlatformMenu(QPlatformMenu *menu) platformMenu = menu; if (!platformMenu.isNull()) { - QObject::connect(platformMenu, SIGNAL(aboutToShow()), q, SIGNAL(aboutToShow())); + QObject::connect(platformMenu, SIGNAL(aboutToShow()), q, SLOT(_q_platformMenuAboutToShow())); QObject::connect(platformMenu, SIGNAL(aboutToHide()), q, SIGNAL(aboutToHide())); } } @@ -1091,9 +1094,6 @@ void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e QAccessibleEvent focusEvent(q, QAccessible::Focus); focusEvent.setChild(actionIndex); QAccessible::updateAccessibility(&focusEvent); - QAccessibleEvent selectionEvent(q, QAccessible::Selection); - focusEvent.setChild(actionIndex); - QAccessible::updateAccessibility(&selectionEvent); } #endif action->showStatusText(topCausedWidget()); @@ -1107,6 +1107,8 @@ void QMenuPrivate::_q_actionTriggered() Q_Q(QMenu); if (QAction *action = qobject_cast(q->sender())) { QPointer actionGuard = action; + if (platformMenu && widgetItems.value(action)) + platformMenu->dismiss(); emit q->triggered(action); if (!activationRecursionGuard && actionGuard) { //in case the action has not been activated by the mouse @@ -1137,6 +1139,24 @@ void QMenuPrivate::_q_actionHovered() } } +void QMenuPrivate::_q_platformMenuAboutToShow() +{ + Q_Q(QMenu); + +#ifdef Q_OS_OSX + if (platformMenu) + Q_FOREACH (QAction *action, q->actions()) + if (QWidget *widget = widgetItems.value(const_cast(action))) + if (widget->parent() == q) { + QPlatformMenuItem *menuItem = platformMenu->menuItemForTag(reinterpret_cast(action)); + moveWidgetToPlatformItem(widget, menuItem); + platformMenu->syncMenuItem(menuItem); + } +#endif + + emit q->aboutToShow(); +} + bool QMenuPrivate::hasMouseMoved(const QPoint &globalPos) { //determines if the mouse has moved (ie its initial position has @@ -2999,8 +3019,19 @@ void QMenu::actionEvent(QActionEvent *e) if (e->action() == d->currentAction) d->currentAction = 0; if (QWidgetAction *wa = qobject_cast(e->action())) { - if (QWidget *widget = d->widgetItems.value(wa)) + if (QWidget *widget = d->widgetItems.value(wa)) { +#ifdef Q_OS_OSX + QWidget *p = widget->parentWidget(); + if (p != this && qobject_cast(p)) { + // This widget was reparented into a native Mac view + // (see QMenuPrivate::moveWidgetToPlatformItem). + // Reset the parent and delete the native widget. + widget->setParent(this); + p->deleteLater(); + } +#endif wa->releaseWidget(widget); + } } d->widgetItems.remove(e->action()); } diff --git a/src/widgets/widgets/qmenu.h b/src/widgets/widgets/qmenu.h index 8a8eaf3bae..fef7903278 100644 --- a/src/widgets/widgets/qmenu.h +++ b/src/widgets/widgets/qmenu.h @@ -195,6 +195,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_actionTriggered()) Q_PRIVATE_SLOT(d_func(), void _q_actionHovered()) Q_PRIVATE_SLOT(d_func(), void _q_overrideMenuActionDestroyed()) + Q_PRIVATE_SLOT(d_func(), void _q_platformMenuAboutToShow()) protected: QMenu(QMenuPrivate &dd, QWidget* parent = 0); diff --git a/src/widgets/widgets/qmenu_mac.mm b/src/widgets/widgets/qmenu_mac.mm index 41c4481b74..5e304d058b 100644 --- a/src/widgets/widgets/qmenu_mac.mm +++ b/src/widgets/widgets/qmenu_mac.mm @@ -44,6 +44,8 @@ #include "qmenu.h" #include "qmenubar.h" +#include "qmenubar_p.h" +#include "qmacnativewidget_mac.h" #include #include @@ -115,6 +117,23 @@ void QMenu::setAsDockMenu() \sa QMenu:setAsDockMenu() */ +void QMenuPrivate::moveWidgetToPlatformItem(QWidget *widget, QPlatformMenuItem* item) +{ + QMacNativeWidget *container = new QMacNativeWidget; + QObject::connect(platformMenu, SIGNAL(destroyed()), container, SLOT(deleteLater())); + container->resize(widget->sizeHint()); + widget->setParent(container); + + NSView *containerView = container->nativeView(); + QWindow *containerWindow = container->windowHandle(); + Qt::WindowFlags wf = containerWindow->flags(); + containerWindow->setFlags(wf | Qt::SubWindow); + [(NSView *)widget->winId() setAutoresizingMask:NSViewWidthSizable]; + + item->setNativeContents((WId)containerView); + container->show(); +} + #endif //QT_NO_MENU #ifndef QT_NO_MENUBAR diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h index 9d9851af64..71bf33e1ce 100644 --- a/src/widgets/widgets/qmenu_p.h +++ b/src/widgets/widgets/qmenu_p.h @@ -110,6 +110,9 @@ public: void init(); void setPlatformMenu(QPlatformMenu *menu); void syncPlatformMenu(); +#ifdef Q_OS_OSX + void moveWidgetToPlatformItem(QWidget *w, QPlatformMenuItem* item); +#endif static QMenuPrivate *get(QMenu *m) { return m->d_func(); } int scrollerHeight() const; @@ -223,6 +226,7 @@ public: void _q_actionTriggered(); void _q_actionHovered(); + void _q_platformMenuAboutToShow(); bool hasMouseMoved(const QPoint &globalPos); diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 03ab490823..729e08c7a5 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -531,9 +531,6 @@ void QMenuBarPrivate::_q_actionHovered() QAccessibleEvent focusEvent(q, QAccessible::Focus); focusEvent.setChild(actionIndex); QAccessible::updateAccessibility(&focusEvent); - QAccessibleEvent selectionEvent(q, QAccessible::Selection); - selectionEvent.setChild(actionIndex); - QAccessible::updateAccessibility(&selectionEvent); } #endif //QT_NO_ACCESSIBILITY } diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp index 4b434822b8..9d91ce42a5 100644 --- a/src/xml/sax/qxml.cpp +++ b/src/xml/sax/qxml.cpp @@ -3247,7 +3247,7 @@ void QXmlSimpleReader::setFeature(const QString& name, bool enable) || name == QLatin1String("http://qt-project.org/xml/features/report-whitespace-only-CharData")) { d->reportWhitespaceCharData = enable; } else if (name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity") // For compat with Qt 4 - || name == QLatin1String("http://trolltech.com/xml/features/report-start-end-entity")) { + || name == QLatin1String("http://qt-project.org/xml/features/report-start-end-entity")) { d->reportEntities = enable; } else { qWarning("Unknown feature %s", name.toLatin1().data()); diff --git a/tests/auto/corelib/codecs/utf8/tst_utf8.cpp b/tests/auto/corelib/codecs/utf8/tst_utf8.cpp index b00fd0dfd4..d1aadab7d8 100644 --- a/tests/auto/corelib/codecs/utf8/tst_utf8.cpp +++ b/tests/auto/corelib/codecs/utf8/tst_utf8.cpp @@ -53,11 +53,7 @@ public: // test data: QTextCodec *codec; QString (*from8BitPtr)(const char *, int); -#ifdef Q_COMPILER_REF_QUALIFIERS - QByteArray (QString:: *to8Bit)() const &; -#else - QByteArray (QString:: *to8Bit)() const; -#endif + static QByteArray to8Bit(const QString &); inline QString from8Bit(const QByteArray &ba) { return from8BitPtr(ba.constData(), ba.length()); } @@ -97,14 +93,21 @@ void tst_Utf8::init() if (useLocale) { codec = QTextCodec::codecForLocale(); from8BitPtr = &QString::fromLocal8Bit; - to8Bit = &QString::toLocal8Bit; } else { codec = QTextCodec::codecForMib(106); from8BitPtr = &QString::fromUtf8; - to8Bit = &QString::toUtf8; } } +QByteArray tst_Utf8::to8Bit(const QString &s) +{ + QFETCH_GLOBAL(bool, useLocale); + if (useLocale) + return s.toLocal8Bit(); + else + return s.toUtf8(); +} + void tst_Utf8::roundTrip_data() { QTest::addColumn("utf8"); @@ -114,10 +117,10 @@ void tst_Utf8::roundTrip_data() QTest::newRow("nul") << QByteArray("", 1) << QString(QChar(QChar::Null)); static const char ascii[] = "This is a standard US-ASCII message"; - QTest::newRow("ascii") << QByteArray(ascii) << ascii; + QTest::newRow("ascii") << QByteArray(ascii) << QString::fromLatin1(ascii); static const char ascii2[] = "\1This\2is\3an\4US-ASCII\020 message interspersed with control chars"; - QTest::newRow("ascii2") << QByteArray(ascii2) << ascii2; + QTest::newRow("ascii2") << QByteArray(ascii2) << QString::fromLatin1(ascii2); static const char utf8_1[] = "\302\240"; // NBSP QTest::newRow("utf8_1") << QByteArray(utf8_1) << QString(QChar(QChar::Nbsp)); @@ -161,11 +164,20 @@ void tst_Utf8::roundTrip() QFETCH(QByteArray, utf8); QFETCH(QString, utf16); - QCOMPARE((utf16.*to8Bit)(), utf8); + QCOMPARE(to8Bit(utf16), utf8); QCOMPARE(from8Bit(utf8), utf16); - QCOMPARE((from8Bit(utf8).*to8Bit)(), utf8); - QCOMPARE(from8Bit((utf16.*to8Bit)()), utf16); + QCOMPARE(to8Bit(from8Bit(utf8)), utf8); + QCOMPARE(from8Bit(to8Bit(utf16)), utf16); + + // repeat with a longer message + utf8.prepend("12345678901234"); + utf16.prepend(QLatin1String("12345678901234")); + QCOMPARE(to8Bit(utf16), utf8); + QCOMPARE(from8Bit(utf8), utf16); + + QCOMPARE(to8Bit(from8Bit(utf8)), utf8); + QCOMPARE(from8Bit(to8Bit(utf16)), utf16); } void tst_Utf8::charByChar_data() diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp index a58c7dfb4b..4f7ddce9c3 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp +++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. @@ -405,6 +405,13 @@ void tst_QFileSystemWatcher::removePaths() watcher.removePaths(paths); } +static QByteArray msgFileOperationFailed(const char *what, const QFile &f) +{ + return what + QByteArrayLiteral(" failed on \"") + + QDir::toNativeSeparators(f.fileName()).toLocal8Bit() + + QByteArrayLiteral("\": ") + f.errorString().toLocal8Bit(); +} + void tst_QFileSystemWatcher::watchFileAndItsDirectory() { QFETCH(QString, backend); @@ -420,14 +427,10 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() QString testFileName = testDir.filePath("testFile.txt"); QString secondFileName = testDir.filePath("testFile2.txt"); - QFile::remove(secondFileName); QFile testFile(testFileName); - testFile.setPermissions(QFile::ReadOwner | QFile::WriteOwner); - testFile.remove(); - - QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); - testFile.write(QByteArray("hello")); + QVERIFY2(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate), msgFileOperationFailed("open", testFile)); + QVERIFY2(testFile.write(QByteArrayLiteral("hello")) > 0, msgFileOperationFailed("write", testFile)); testFile.close(); QFileSystemWatcher watcher; @@ -449,8 +452,8 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() // wait before modifying the directory... QTest::qWait(2000); - QVERIFY(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate)); - testFile.write(QByteArray("hello again")); + QVERIFY2(testFile.open(QIODevice::WriteOnly | QIODevice::Truncate), msgFileOperationFailed("open", testFile)); + QVERIFY2(testFile.write(QByteArrayLiteral("hello again")), msgFileOperationFailed("write", testFile)); testFile.close(); #ifdef Q_OS_MAC @@ -472,8 +475,8 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() fileChangedSpy.clear(); dirChangedSpy.clear(); QFile secondFile(secondFileName); - secondFile.open(QIODevice::WriteOnly | QIODevice::Truncate); - secondFile.write("Foo"); + QVERIFY2(secondFile.open(QIODevice::WriteOnly | QIODevice::Truncate), msgFileOperationFailed("open", secondFile)); + QVERIFY2(secondFile.write(QByteArrayLiteral("Foo")) > 0, msgFileOperationFailed("write", secondFile)); secondFile.close(); timer.start(3000); @@ -491,17 +494,17 @@ void tst_QFileSystemWatcher::watchFileAndItsDirectory() dirChangedSpy.clear(); - QFile::remove(testFileName); + QVERIFY(QFile::remove(testFileName)); QTRY_VERIFY(fileChangedSpy.count() > 0); - QCOMPARE(dirChangedSpy.count(), 1); + QTRY_COMPARE(dirChangedSpy.count(), 1); fileChangedSpy.clear(); dirChangedSpy.clear(); // removing a deleted file should fail QVERIFY(!watcher.removePath(testFileName)); - QFile::remove(secondFileName); + QVERIFY(QFile::remove(secondFileName)); timer.start(3000); eventLoop.exec(); diff --git a/tests/auto/corelib/tools/qarraydata/simplevector.h b/tests/auto/corelib/tools/qarraydata/simplevector.h index 40917c0172..af0ced130c 100644 --- a/tests/auto/corelib/tools/qarraydata/simplevector.h +++ b/tests/auto/corelib/tools/qarraydata/simplevector.h @@ -101,9 +101,10 @@ public: bool isStatic() const { return d->ref.isStatic(); } bool isShared() const { return d->ref.isShared(); } bool isSharedWith(const SimpleVector &other) const { return d == other.d; } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) bool isSharable() const { return d->ref.isSharable(); } - void setSharable(bool sharable) { d.setSharable(sharable); } +#endif size_t size() const { return d->size; } size_t capacity() const { return d->alloc; } diff --git a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 60b807a7bc..35ec0ef019 100644 --- a/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -52,7 +52,9 @@ struct SharedNullVerifier { Q_ASSERT(QArrayData::shared_null[0].ref.isStatic()); Q_ASSERT(QArrayData::shared_null[0].ref.isShared()); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) Q_ASSERT(QArrayData::shared_null[0].ref.isSharable()); +#endif } }; @@ -107,7 +109,9 @@ void tst_QArrayData::referenceCounting() QCOMPARE(array.ref.atomic.load(), 1); QVERIFY(!array.ref.isStatic()); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QVERIFY(array.ref.isSharable()); +#endif QVERIFY(array.ref.ref()); QCOMPARE(array.ref.atomic.load(), 2); @@ -127,6 +131,7 @@ void tst_QArrayData::referenceCounting() // Now would be a good time to free/release allocated data } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) { // Reference counting initialized to 0 (non-sharable) QArrayData array = { { Q_BASIC_ATOMIC_INITIALIZER(0) }, 0, 0, 0, 0 }; @@ -145,6 +150,7 @@ void tst_QArrayData::referenceCounting() // Free/release data } +#endif { // Reference counting initialized to -1 (static read-only data) @@ -153,13 +159,16 @@ void tst_QArrayData::referenceCounting() QCOMPARE(array.ref.atomic.load(), -1); QVERIFY(array.ref.isStatic()); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QVERIFY(array.ref.isSharable()); +#endif QVERIFY(array.ref.ref()); QCOMPARE(array.ref.atomic.load(), -1); QVERIFY(array.ref.deref()); QCOMPARE(array.ref.atomic.load(), -1); + } } @@ -169,16 +178,19 @@ void tst_QArrayData::sharedNullEmpty() QArrayData *empty = QArrayData::allocate(1, Q_ALIGNOF(QArrayData), 0); QVERIFY(null->ref.isStatic()); - QVERIFY(null->ref.isSharable()); QVERIFY(null->ref.isShared()); QVERIFY(empty->ref.isStatic()); - QVERIFY(empty->ref.isSharable()); QVERIFY(empty->ref.isShared()); QCOMPARE(null->ref.atomic.load(), -1); QCOMPARE(empty->ref.atomic.load(), -1); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + QVERIFY(null->ref.isSharable()); + QVERIFY(empty->ref.isSharable()); +#endif + QVERIFY(null->ref.ref()); QVERIFY(empty->ref.ref()); @@ -305,6 +317,7 @@ void tst_QArrayData::simpleVector() QVERIFY(!v7.isShared()); QVERIFY(!v8.isShared()); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QVERIFY(v1.isSharable()); QVERIFY(v2.isSharable()); QVERIFY(v3.isSharable()); @@ -313,6 +326,7 @@ void tst_QArrayData::simpleVector() QVERIFY(v6.isSharable()); QVERIFY(v7.isSharable()); QVERIFY(v8.isSharable()); +#endif QVERIFY(v1.isSharedWith(v2)); QVERIFY(v1.isSharedWith(v3)); @@ -496,6 +510,7 @@ void tst_QArrayData::simpleVector() for (int i = 0; i < 120; ++i) QCOMPARE(v1[i], v8[i % 10]); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) { v7.setSharable(true); QVERIFY(v7.isSharable()); @@ -558,6 +573,7 @@ void tst_QArrayData::simpleVector() QVERIFY(null.isEmpty()); QVERIFY(empty.isEmpty()); } +#endif } Q_DECLARE_METATYPE(SimpleVector) @@ -648,7 +664,7 @@ void tst_QArrayData::allocate_data() QTest::addColumn("alignment"); QTest::addColumn("allocateOptions"); QTest::addColumn("isCapacityReserved"); - QTest::addColumn("isSharable"); + QTest::addColumn("isSharable"); // ### Qt6: remove QTest::addColumn("commonEmpty"); struct { @@ -662,10 +678,12 @@ void tst_QArrayData::allocate_data() }; QArrayData *shared_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0); - QArrayData *unsharable_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0, QArrayData::Unsharable); - QVERIFY(shared_empty); + +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + QArrayData *unsharable_empty = QArrayData::allocate(0, Q_ALIGNOF(QArrayData), 0, QArrayData::Unsharable); QVERIFY(unsharable_empty); +#endif struct { char const *description; @@ -676,10 +694,12 @@ void tst_QArrayData::allocate_data() } options[] = { { "Default", QArrayData::Default, false, true, shared_empty }, { "Reserved", QArrayData::CapacityReserved, true, true, shared_empty }, +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) { "Reserved | Unsharable", QArrayData::CapacityReserved | QArrayData::Unsharable, true, false, unsharable_empty }, { "Unsharable", QArrayData::Unsharable, false, false, unsharable_empty }, +#endif { "Grow", QArrayData::Grow, false, true, shared_empty } }; @@ -700,7 +720,6 @@ void tst_QArrayData::allocate() QFETCH(size_t, alignment); QFETCH(QArrayData::AllocationOptions, allocateOptions); QFETCH(bool, isCapacityReserved); - QFETCH(bool, isSharable); QFETCH(const QArrayData *, commonEmpty); // Minimum alignment that can be requested is that of QArrayData. @@ -725,7 +744,10 @@ void tst_QArrayData::allocate() else QCOMPARE(data->alloc, uint(capacity)); QCOMPARE(data->capacityReserved, uint(isCapacityReserved)); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + QFETCH(bool, isSharable); QCOMPARE(data->ref.isSharable(), isSharable); +#endif // Check that the allocated array can be used. Best tested with a // memory checker, such as valgrind, running. @@ -1302,6 +1324,7 @@ static inline bool arrayIsFilledWith(const QArrayDataPointer &array, void tst_QArrayData::setSharable_data() { +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QTest::addColumn >("array"); QTest::addColumn("size"); QTest::addColumn("capacity"); @@ -1342,10 +1365,12 @@ void tst_QArrayData::setSharable_data() QTest::newRow("non-empty-reserved") << nonEmptyReserved << size_t(7) << size_t(15) << true << 2; QTest::newRow("static-array") << staticArray << size_t(10) << size_t(0) << false << 3; QTest::newRow("raw-data") << rawData << size_t(10) << size_t(0) << false << 3; +#endif } void tst_QArrayData::setSharable() { +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QFETCH(QArrayDataPointer, array); QFETCH(size_t, size); QFETCH(size_t, capacity); @@ -1424,6 +1449,7 @@ void tst_QArrayData::setSharable() QCOMPARE(array->ref.isShared(), !(size || isCapacityReserved)); QVERIFY(array->ref.isSharable()); +#endif } struct ResetOnDtor @@ -1474,6 +1500,7 @@ void fromRawData_impl() QVERIFY((const T *)raw.constBegin() != array); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) { // Immutable, unsharable SimpleVector raw = SimpleVector::fromRawData(array, @@ -1502,6 +1529,7 @@ void fromRawData_impl() QCOMPARE(raw.back(), T(11)); QVERIFY((const T *)raw.constBegin() != array); } +#endif } void tst_QArrayData::fromRawData_data() @@ -1558,7 +1586,9 @@ void tst_QArrayData::literals() QVERIFY(v.isStatic()); #endif +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QVERIFY(v.isSharable()); +#endif QCOMPARE((void*)(const char*)(v.constBegin() + v.size()), (void*)(const char*)v.constEnd()); for (int i = 0; i < 10; ++i) @@ -1607,7 +1637,9 @@ void tst_QArrayData::variadicLiterals() QVERIFY(v.isStatic()); +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QVERIFY(v.isSharable()); +#endif QCOMPARE((const int *)(v.constBegin() + v.size()), (const int *)v.constEnd()); for (int i = 0; i < 7; ++i) diff --git a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp index 6e183f3212..cdcbd19ae8 100644 --- a/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp +++ b/tests/auto/corelib/tools/qbytearray/tst_qbytearray.cpp @@ -1863,7 +1863,7 @@ void tst_QByteArray::reserve() QCOMPARE(qba.capacity(), capacity); QCOMPARE(copy.capacity(), capacity); - copy = qba; + qba = copy; qba.reserve(capacity * 2); QCOMPARE(qba.size(), capacity); QCOMPARE(qba.capacity(), capacity * 2); diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp index 73f8973245..9c96aaf78d 100644 --- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -1217,12 +1217,14 @@ void tst_QHash::noNeedlessRehashes() void tst_QHash::const_shared_null() { + QHash hash2; +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QHash hash1; hash1.setSharable(false); QVERIFY(hash1.isDetached()); - QHash hash2; hash2.setSharable(true); +#endif QVERIFY(!hash2.isDetached()); } diff --git a/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp index 49b32d5534..9e47e9c6d6 100644 --- a/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp +++ b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp @@ -1018,12 +1018,14 @@ void tst_QLinkedList::initializeList() const template void tst_QLinkedList::constSharedNull() const { + QLinkedList list2; +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QLinkedList list1; list1.setSharable(false); QVERIFY(list1.isDetached()); - QLinkedList list2; list2.setSharable(true); +#endif QVERIFY(!list2.isDetached()); } @@ -1049,6 +1051,7 @@ void tst_QLinkedList::constSharedNullComplex() const void tst_QLinkedList::setSharableInt() const { +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QLinkedList orglist; orglist << 0 << 1 << 2 << 3 << 4 << 5; int size = 6; @@ -1094,6 +1097,7 @@ void tst_QLinkedList::setSharableInt() const } QCOMPARE(list.size(), size); +#endif } QTEST_APPLESS_MAIN(tst_QLinkedList) diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp index d77cc4a37c..b368359c62 100644 --- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp +++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp @@ -1522,12 +1522,14 @@ void tst_QList::initializeList() const template void tst_QList::constSharedNull() const { + QList list2; +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QList list1; list1.setSharable(false); QVERIFY(list1.isDetached()); - QList list2; list2.setSharable(true); +#endif QVERIFY(!list2.isDetached()); } @@ -1553,16 +1555,19 @@ void tst_QList::constSharedNullComplex() const template void generateSetSharableData() { +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QTest::addColumn >("list"); QTest::addColumn("size"); QTest::newRow("null") << QList() << 0; QTest::newRow("non-empty") << (QList() << T(0) << T(1) << T(2) << T(3) << T(4)) << 5; +#endif } template void runSetSharableTest() { +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QFETCH(QList, list); QFETCH(int, size); @@ -1602,6 +1607,7 @@ void runSetSharableTest() QCOMPARE(int(list[i]), i); QCOMPARE(list.size(), size); +#endif } void tst_QList::setSharableInt_data() const diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp index e812e5a337..00e669c1d8 100644 --- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -984,12 +984,14 @@ void tst_QMap::qmultimap_specific() void tst_QMap::const_shared_null() { + QMap map2; +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QMap map1; map1.setSharable(false); QVERIFY(map1.isDetached()); - QMap map2; map2.setSharable(true); +#endif QVERIFY(!map2.isDetached()); } @@ -1046,6 +1048,7 @@ const T &const_(const T &t) void tst_QMap::setSharable() { +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) QMap map; map.insert(1, "um"); @@ -1095,6 +1098,7 @@ void tst_QMap::setSharable() QVERIFY(!map.isDetached()); QVERIFY(copy.isSharedWith(map)); } +#endif } void tst_QMap::insert() @@ -1204,7 +1208,6 @@ void tst_QMap::initializerList() void tst_QMap::testInsertWithHint() { QMap map; - map.setSharable(false); // Check with end hint(); map.insert(map.constEnd(), 3, 1); // size == 1 @@ -1268,7 +1271,6 @@ void tst_QMap::testInsertWithHint() void tst_QMap::testInsertMultiWithHint() { QMap map; - map.setSharable(false); typedef QMap::const_iterator cite; // Hack since we define QT_STRICT_ITERATORS map.insertMulti(cite(map.end()), 64, 65); diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index d9d6b985b7..95d377b176 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -3619,6 +3619,14 @@ void tst_QString::fromUtf8_data() str += " some "; QTest::newRow("str3-len") << QByteArray("\342\202\254 some text") << str << 9; + // test that QString::fromUtf8 suppresses an initial BOM, but not a ZWNBSP + str = "hello"; + QByteArray bom("\357\273\277"); + QTest::newRow("bom0") << bom << QString() << 3; + QTest::newRow("bom1") << bom + "hello" << str << -1; + QTest::newRow("bom+zwnbsp0") << bom + bom << QString(QChar(0xfeff)) << -1; + QTest::newRow("bom+zwnbsp1") << bom + "hello" + bom << str + QChar(0xfeff) << -1; + str = "hello"; str += QChar::ReplacementCharacter; str += QChar(0x68); diff --git a/tests/auto/corelib/tools/qvector/tst_qvector.cpp b/tests/auto/corelib/tools/qvector/tst_qvector.cpp index f85d2dee0c..776251fa52 100644 --- a/tests/auto/corelib/tools/qvector/tst_qvector.cpp +++ b/tests/auto/corelib/tools/qvector/tst_qvector.cpp @@ -267,12 +267,15 @@ private slots: void initializeListCustom(); void const_shared_null(); +#if 1 + // ### Qt6 remove this section void setSharableInt_data(); void setSharableInt(); void setSharableMovable_data(); void setSharableMovable(); void setSharableCustom_data(); void setSharableCustom(); +#endif void detachInt() const; void detachMovable() const; @@ -396,6 +399,14 @@ void tst_QVector::copyConstructor() const QVector v2(v1); QCOMPARE(v1, v2); } + { + QVector v1; + v1 << value1 << value2 << value3 << value4; + QVector v2(v1); + QCOMPARE(v1, v2); + } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section { QVector v1; v1.setSharable(false); @@ -403,12 +414,6 @@ void tst_QVector::copyConstructor() const QVERIFY(!v1.isSharedWith(v2)); QCOMPARE(v1, v2); } - { - QVector v1; - v1 << value1 << value2 << value3 << value4; - QVector v2(v1); - QCOMPARE(v1, v2); - } { QVector v1; v1 << value1 << value2 << value3 << value4; @@ -417,6 +422,7 @@ void tst_QVector::copyConstructor() const QVERIFY(!v1.isSharedWith(v2)); QCOMPARE(v1, v2); } +#endif } void tst_QVector::copyConstructorInt() const @@ -517,6 +523,8 @@ void tst_QVector::append() const QVERIFY(v.size() == 3); QCOMPARE(v.at(v.size() - 1), SimpleValue::at(0)); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section { QVector v(2); v.reserve(12); @@ -525,6 +533,7 @@ void tst_QVector::append() const QVERIFY(v.size() == 3); QCOMPARE(v.last(), SimpleValue::at(0)); } +#endif } void tst_QVector::appendInt() const @@ -822,12 +831,15 @@ void tst_QVector::eraseEmpty() const v.erase(v.begin(), v.end()); QCOMPARE(v.size(), 0); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section { QVector v; v.setSharable(false); v.erase(v.begin(), v.end()); QCOMPARE(v.size(), 0); } +#endif } void tst_QVector::eraseEmptyInt() const @@ -858,6 +870,8 @@ void tst_QVector::eraseEmptyReserved() const v.erase(v.begin(), v.end()); QCOMPARE(v.size(), 0); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section { QVector v; v.reserve(10); @@ -865,6 +879,7 @@ void tst_QVector::eraseEmptyReserved() const v.erase(v.begin(), v.end()); QCOMPARE(v.size(), 0); } +#endif } void tst_QVector::eraseEmptyReservedInt() const @@ -971,6 +986,8 @@ void tst_QVector::erase(bool shared) const if (shared) QCOMPARE(SimpleValue::vector(12), *svc.copy); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section { QVector v = SimpleValue::vector(10); SharedVectorChecker svc(v, shared); @@ -983,6 +1000,7 @@ void tst_QVector::erase(bool shared) const if (shared) QCOMPARE(SimpleValue::vector(10), *svc.copy); } +#endif } void tst_QVector::eraseInt() const @@ -1055,6 +1073,8 @@ template void tst_QVector::eraseReserved() const v.erase(v.begin() + 1, v.end() - 1); QCOMPARE(v.size(), 2); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section { QVector v(10); v.reserve(16); @@ -1064,6 +1084,7 @@ template void tst_QVector::eraseReserved() const v.erase(v.begin(), v.end() - 1); QCOMPARE(v.size(), 1); } +#endif } void tst_QVector::eraseReservedInt() const @@ -1585,6 +1606,14 @@ void tst_QVector::resizePOD_data() const QVERIFY(emptyReserved.capacity() >= 10); QVERIFY(nonEmptyReserved.capacity() >= 15); + QTest::newRow("null") << null << 10; + QTest::newRow("empty") << empty << 10; + QTest::newRow("emptyReserved") << emptyReserved << 10; + QTest::newRow("nonEmpty") << nonEmpty << 10; + QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; + +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section QVector nullNotShared; QVector emptyNotShared(0, 5); QVector emptyReservedNotShared; @@ -1603,16 +1632,12 @@ void tst_QVector::resizePOD_data() const nonEmptyNotShared.setSharable(false); nonEmptyReservedNotShared.setSharable(false); - QTest::newRow("null") << null << 10; - QTest::newRow("empty") << empty << 10; - QTest::newRow("emptyReserved") << emptyReserved << 10; - QTest::newRow("nonEmpty") << nonEmpty << 10; - QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; QTest::newRow("nullNotShared") << nullNotShared << 10; QTest::newRow("emptyNotShared") << emptyNotShared << 10; QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; +#endif } void tst_QVector::resizePOD() const @@ -1656,6 +1681,14 @@ void tst_QVector::resizeComplexMovable_data() const QVERIFY(emptyReserved.capacity() >= 10); QVERIFY(nonEmptyReserved.capacity() >= 15); + QTest::newRow("null") << null << 10; + QTest::newRow("empty") << empty << 10; + QTest::newRow("emptyReserved") << emptyReserved << 10; + QTest::newRow("nonEmpty") << nonEmpty << 10; + QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; + +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section QVector nullNotShared; QVector emptyNotShared(0, 'Q'); QVector emptyReservedNotShared; @@ -1674,16 +1707,12 @@ void tst_QVector::resizeComplexMovable_data() const nonEmptyNotShared.setSharable(false); nonEmptyReservedNotShared.setSharable(false); - QTest::newRow("null") << null << 10; - QTest::newRow("empty") << empty << 10; - QTest::newRow("emptyReserved") << emptyReserved << 10; - QTest::newRow("nonEmpty") << nonEmpty << 10; - QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; QTest::newRow("nullNotShared") << nullNotShared << 10; QTest::newRow("emptyNotShared") << emptyNotShared << 10; QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; +#endif } void tst_QVector::resizeComplexMovable() const @@ -1731,6 +1760,14 @@ void tst_QVector::resizeComplex_data() const QVERIFY(emptyReserved.capacity() >= 10); QVERIFY(nonEmptyReserved.capacity() >= 15); + QTest::newRow("null") << null << 10; + QTest::newRow("empty") << empty << 10; + QTest::newRow("emptyReserved") << emptyReserved << 10; + QTest::newRow("nonEmpty") << nonEmpty << 10; + QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; + +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section QVector nullNotShared; QVector emptyNotShared(0, '0'); QVector emptyReservedNotShared; @@ -1749,16 +1786,12 @@ void tst_QVector::resizeComplex_data() const nonEmptyNotShared.setSharable(false); nonEmptyReservedNotShared.setSharable(false); - QTest::newRow("null") << null << 10; - QTest::newRow("empty") << empty << 10; - QTest::newRow("emptyReserved") << emptyReserved << 10; - QTest::newRow("nonEmpty") << nonEmpty << 10; - QTest::newRow("nonEmptyReserved") << nonEmptyReserved << 10; QTest::newRow("nullNotShared") << nullNotShared << 10; QTest::newRow("emptyNotShared") << emptyNotShared << 10; QTest::newRow("emptyReservedNotShared") << emptyReservedNotShared << 10; QTest::newRow("nonEmptyNotShared") << nonEmptyNotShared << 10; QTest::newRow("nonEmptyReservedNotShared") << nonEmptyReservedNotShared << 10; +#endif } void tst_QVector::resizeComplex() const @@ -2143,15 +2176,20 @@ void tst_QVector::initializeListCustom() void tst_QVector::const_shared_null() { + QVector v2; +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) + // ### Qt6 remove this section QVector v1; v1.setSharable(false); QVERIFY(v1.isDetached()); - QVector v2; v2.setSharable(true); +#endif QVERIFY(!v2.isDetached()); } +#if QT_SUPPORTS(UNSHARABLE_CONTAINERS) +// ### Qt6 remove this section template void tst_QVector::setSharable_data() const { @@ -2182,21 +2220,6 @@ void tst_QVector::setSharable_data() const QTest::newRow("non-empty, Reserved") << nonEmptyReserved << 7 << 15 << true; } -void tst_QVector::setSharableInt_data() -{ - setSharable_data(); -} - -void tst_QVector::setSharableMovable_data() -{ - setSharable_data(); -} - -void tst_QVector::setSharableCustom_data() -{ - setSharable_data(); -} - template void tst_QVector::setSharable() const { @@ -2258,6 +2281,30 @@ void tst_QVector::setSharable() const .arg(vector.capacity()) .arg(capacity))); } +#else +template void tst_QVector::setSharable_data() const +{ +} + +template void tst_QVector::setSharable() const +{ +} +#endif + +void tst_QVector::setSharableInt_data() +{ + setSharable_data(); +} + +void tst_QVector::setSharableMovable_data() +{ + setSharable_data(); +} + +void tst_QVector::setSharableCustom_data() +{ + setSharable_data(); +} void tst_QVector::setSharableInt() { diff --git a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp index eea72cd246..e1cdb8db45 100644 --- a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp +++ b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp @@ -48,6 +48,10 @@ #include #include +#if defined(Q_OS_QNX) +#include +#endif + #include #include "tst_qcoreapplication.h" @@ -143,6 +147,9 @@ void tst_QGuiApplication::focusObject() const QRect screenGeometry = QGuiApplication::primaryScreen()->availableVirtualGeometry(); DummyWindow window1; +#if defined(Q_OS_QNX) + window1.setSurfaceType(QSurface::OpenGLSurface); +#endif window1.resize(windowSize, windowSize); window1.setTitle(QStringLiteral("focusObject:window1")); window1.setFramePosition(QPoint(screenGeometry.left() + spacing, screenGeometry.top() + spacing)); @@ -153,6 +160,15 @@ void tst_QGuiApplication::focusObject() window1.show(); +#if defined(Q_OS_QNX) // We either need to create a eglSurface or a create a backing store + // and then post the window in order for screen to show the window + QOpenGLContext context; + context.create(); + context.makeCurrent(&window1); + QTest::qWaitForWindowExposed(&window1); // Buffer swap only succeeds with exposed window + context.swapBuffers(&window1); +#endif + QSignalSpy spy(&app, SIGNAL(focusObjectChanged(QObject*))); @@ -298,15 +314,35 @@ void tst_QGuiApplication::changeFocusWindow() // focus is changed between FocusAboutToChange and FocusChanged FocusChangeWindow window1; +#if defined(Q_OS_QNX) + window1.setSurfaceType(QSurface::OpenGLSurface); +#endif window1.resize(windowSize, windowSize); window1.setFramePosition(QPoint(screenGeometry.left() + spacing, screenGeometry.top() + spacing)); window1.setTitle(QStringLiteral("changeFocusWindow:window1")); window1.show(); +#if defined(Q_OS_QNX) // We either need to create a eglSurface or a create a backing store + // and then post the window in order for screen to show the window + QOpenGLContext context; + context.create(); + context.makeCurrent(&window1); + QTest::qWaitForWindowExposed(&window1); // Buffer swap only succeeds with exposed window + context.swapBuffers(&window1); +#endif FocusChangeWindow window2; +#if defined(Q_OS_QNX) + window2.setSurfaceType(QSurface::OpenGLSurface); +#endif window2.resize(windowSize, windowSize); window2.setFramePosition(QPoint(screenGeometry.left() + 2 * spacing + windowSize, screenGeometry.top() + spacing)); window2.setTitle(QStringLiteral("changeFocusWindow:window2")); window2.show(); +#if defined(Q_OS_QNX) // We either need to create a eglSurface or a create a backing store + // and then post the window in order for screen to show the window + context.makeCurrent(&window2); + QTest::qWaitForWindowExposed(&window2); // Buffer swap only succeeds with exposed window + context.swapBuffers(&window2); +#endif QVERIFY(QTest::qWaitForWindowExposed(&window1)); QVERIFY(QTest::qWaitForWindowExposed(&window2)); window1.requestActivate(); diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index eefa85a745..589f3e66e1 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -88,6 +88,10 @@ private slots: void visibility(); void mask(); void initialSize(); + void modalDialog(); + void modalDialogClosingOneOfTwoModal(); + void modalWithChildWindow(); + void modalWindowModallity(); void initTestCase() { @@ -1316,6 +1320,115 @@ void tst_QWindow::initialSize() } } +void tst_QWindow::modalDialog() +{ + QWindow normalWindow; + normalWindow.resize(400, 400); + normalWindow.show(); + QVERIFY(QTest::qWaitForWindowExposed(&normalWindow)); + + QWindow dialog; + dialog.resize(200,200); + dialog.setModality(Qt::ApplicationModal); + dialog.setFlags(Qt::Dialog); + dialog.show(); + QVERIFY(QTest::qWaitForWindowExposed(&dialog)); + + normalWindow.requestActivate(); + + QGuiApplication::sync(); + QGuiApplication::processEvents(); + QTRY_COMPARE(QGuiApplication::focusWindow(), &dialog); +} + +void tst_QWindow::modalDialogClosingOneOfTwoModal() +{ + QWindow normalWindow; + normalWindow.resize(400, 400); + normalWindow.show(); + QVERIFY(QTest::qWaitForWindowExposed(&normalWindow)); + + QWindow first_dialog; + first_dialog.resize(200,200); + first_dialog.setModality(Qt::ApplicationModal); + first_dialog.setFlags(Qt::Dialog); + first_dialog.show(); + QVERIFY(QTest::qWaitForWindowExposed(&first_dialog)); + + { + QWindow second_dialog; + second_dialog.resize(200,200); + second_dialog.setModality(Qt::ApplicationModal); + second_dialog.setFlags(Qt::Dialog); + second_dialog.show(); + QVERIFY(QTest::qWaitForWindowExposed(&second_dialog)); + + QTRY_COMPARE(QGuiApplication::focusWindow(), &second_dialog); + + second_dialog.close(); + } + + QGuiApplication::sync(); + QGuiApplication::processEvents(); + QTRY_COMPARE(QGuiApplication::focusWindow(), &first_dialog); +} + +void tst_QWindow::modalWithChildWindow() +{ + QWindow normalWindow; + normalWindow.resize(400, 400); + normalWindow.show(); + QVERIFY(QTest::qWaitForWindowExposed(&normalWindow)); + + QWindow tlw_dialog; + tlw_dialog.resize(400,200); + tlw_dialog.setModality(Qt::ApplicationModal); + tlw_dialog.setFlags(Qt::Dialog); + tlw_dialog.create(); + + QWindow sub_window(&tlw_dialog); + sub_window.resize(200,300); + sub_window.show(); + + tlw_dialog.show(); + QVERIFY(QTest::qWaitForWindowExposed(&tlw_dialog)); + QVERIFY(QTest::qWaitForWindowExposed(&sub_window)); + + QTRY_COMPARE(QGuiApplication::focusWindow(), &tlw_dialog); + + sub_window.requestActivate(); + QGuiApplication::sync(); + QGuiApplication::processEvents(); + QTRY_COMPARE(QGuiApplication::focusWindow(), &sub_window); +} + +void tst_QWindow::modalWindowModallity() +{ + QWindow normal_window; + normal_window.resize(400, 400); + normal_window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&normal_window)); + + QWindow parent_to_modal; + parent_to_modal.resize(400, 400); + parent_to_modal.show(); + QVERIFY(QTest::qWaitForWindowExposed(&parent_to_modal)); + QTRY_COMPARE(QGuiApplication::focusWindow(), &parent_to_modal); + + QWindow modal_dialog; + modal_dialog.resize(400,200); + modal_dialog.setModality(Qt::WindowModal); + modal_dialog.setFlags(Qt::Dialog); + modal_dialog.setTransientParent(&parent_to_modal); + modal_dialog.show(); + QVERIFY(QTest::qWaitForWindowExposed(&modal_dialog)); + QTRY_COMPARE(QGuiApplication::focusWindow(), &modal_dialog); + + normal_window.requestActivate(); + QTRY_COMPARE(QGuiApplication::focusWindow(), &normal_window); + +} + #include QTEST_MAIN(tst_QWindow) diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp index 56d6711dc6..d0482d77e2 100644 --- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp @@ -309,9 +309,6 @@ void tst_QTextLayout::simpleBoundingRect() void tst_QTextLayout::threeLineBoundingRect() { -#if defined(Q_OS_MAC) - QSKIP("QTestFontEngine on the mac does not support logclusters at the moment"); -#endif /* stricter check. break text into three lines */ QString firstWord("hello"); @@ -430,9 +427,6 @@ void tst_QTextLayout::forcedBreaks() void tst_QTextLayout::breakAny() { -#if defined(Q_OS_MAC) - QSKIP("QTestFontEngine on the mac does not support logclusters at the moment"); -#endif QString text = "ABCD"; QTextLayout layout(text, testFont); @@ -473,9 +467,6 @@ void tst_QTextLayout::breakAny() void tst_QTextLayout::noWrap() { -#if defined(Q_OS_MAC) - QSKIP("QTestFontEngine on the mac does not support logclusters at the moment"); -#endif QString text = "AB CD"; QTextLayout layout(text, testFont); @@ -1048,9 +1039,6 @@ void tst_QTextLayout::charWordStopOnLineSeparator() void tst_QTextLayout::xToCursorAtEndOfLine() { -#if defined(Q_OS_MAC) - QSKIP("QTestFontEngine on the mac does not support logclusters at the moment"); -#endif QString text = "FirstLine SecondLine"; text.replace('\n', QChar::LineSeparator); @@ -1112,9 +1100,6 @@ void tst_QTextLayout::graphemeBoundaryForSurrogatePairs() void tst_QTextLayout::tabStops() { -#if defined(Q_OS_MAC) - QSKIP("QTestFontEngine on the mac does not support logclusters at the moment"); -#endif QString txt("Hello there\tworld"); QTextLayout layout(txt, testFont); layout.beginLayout(); @@ -1931,13 +1916,16 @@ void tst_QTextLayout::textWithSurrogates_qtbug15679() void tst_QTextLayout::textWidthWithStackedTextEngine() { QString text = QString::fromUtf8("คลิก ถัดไป เพื่อดำเนินการต่อ"); + QTextLayout layout(text); layout.setCacheEnabled(true); layout.beginLayout(); QTextLine line = layout.createLine(); layout.endLayout(); - QFontMetricsF fm(layout.font()); - QCOMPARE(line.naturalTextWidth(), fm.width(text)); + + QStackTextEngine layout2(text, layout.font()); + + QVERIFY(layout2.width(0, text.size()).toReal() >= line.naturalTextWidth()); } void tst_QTextLayout::textWidthWithLineSeparator() @@ -1958,27 +1946,24 @@ void tst_QTextLayout::textWidthWithLineSeparator() void tst_QTextLayout::cursorInLigatureWithMultipleLines() { -#if !defined(Q_OS_MAC) - QSKIP("This test can only be run on Mac"); -#endif QTextLayout layout("first line finish", QFont("Times", 20)); layout.setCacheEnabled(true); layout.beginLayout(); QTextLine line = layout.createLine(); - line.setLineWidth(70); - line = layout.createLine(); + line.setNumColumns(10); + QTextLine line2 = layout.createLine(); layout.endLayout(); - // The second line will be "finish", with "fi" as a ligature - QEXPECT_FAIL("", "QTBUG-26403", Abort); - QVERIFY(line.cursorToX(0) != line.cursorToX(1)); + // The second line will be "finish" + QCOMPARE(layout.text().mid(line2.textStart(), line2.textLength()), QString::fromLatin1("finish")); + + QVERIFY(line.cursorToX(1) != line.cursorToX(0)); + QCOMPARE(line2.cursorToX(line2.textStart()), line.cursorToX(0)); + QCOMPARE(line2.cursorToX(line2.textStart() + 1), line.cursorToX(1)); } void tst_QTextLayout::xToCursorForLigatures() { -#if !defined(Q_OS_MAC) - QSKIP("This test can only be run on Mac"); -#endif QTextLayout layout("fi", QFont("Times", 20)); layout.setCacheEnabled(true); layout.beginLayout(); @@ -2001,9 +1986,6 @@ void tst_QTextLayout::xToCursorForLigatures() void tst_QTextLayout::cursorInNonStopChars() { -#if defined(Q_OS_MAC) - QSKIP("This test can not be run on Mac"); -#endif QTextLayout layout(QString::fromUtf8("\xE0\xA4\xA4\xE0\xA5\x8D\xE0\xA4\xA8")); layout.setCacheEnabled(true); layout.beginLayout(); diff --git a/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp b/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp index c4db669695..74eb58670b 100644 --- a/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp +++ b/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp @@ -1105,6 +1105,9 @@ void tst_QTextScriptEngine::mirroredChars() void tst_QTextScriptEngine::controlInSyllable_qtbug14204() { +#ifdef Q_OS_MAC + QSKIP("Result differs for HarfBuzz-NG, skip test."); +#endif QFontDatabase db; if (!db.families().contains(QStringLiteral("Aparajita"))) QSKIP("couldn't find 'Aparajita' font"); @@ -1143,6 +1146,10 @@ void tst_QTextScriptEngine::combiningMarks_qtbug15675_data() QTest::addColumn("font"); QTest::addColumn("string"); +#ifdef Q_OS_MAC + QSKIP("Result differs for HarfBuzz-NG, skip test."); +#endif + bool hasTests = false; QStringList families; @@ -1251,36 +1258,37 @@ void tst_QTextScriptEngine::thaiWithZWJ() QTextLayout layout(s, font); QTextEngine *e = layout.engine(); e->itemize(); - QCOMPARE(e->layoutData->items.size(), 11); + QCOMPARE(e->layoutData->items.size(), 3); for (int item = 0; item < e->layoutData->items.size(); ++item) e->shape(item); - QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(7)); // Thai: The ZWJ and ZWNJ characters are inherited, so should be part of the thai script - QCOMPARE(e->layoutData->items[1].num_glyphs, ushort(1)); // Common: The smart quotes cannot be handled by thai, so should be a separate item - QCOMPARE(e->layoutData->items[2].num_glyphs, ushort(1)); // Thai: Thai character - QCOMPARE(e->layoutData->items[3].num_glyphs, ushort(1)); // Common: Ellipsis - QCOMPARE(e->layoutData->items[4].num_glyphs, ushort(1)); // Thai: Thai character - QCOMPARE(e->layoutData->items[5].num_glyphs, ushort(1)); // Common: Smart quote - QCOMPARE(e->layoutData->items[6].num_glyphs, ushort(1)); // Thai: Thai character - QCOMPARE(e->layoutData->items[7].num_glyphs, ushort(1)); // Common: \xA0 = non-breaking space. Could be useful to have in thai, but not currently implemented - QCOMPARE(e->layoutData->items[8].num_glyphs, ushort(1)); // Thai: Thai character - QCOMPARE(e->layoutData->items[9].num_glyphs, ushort(1)); // Japanese: Kanji for tree - QCOMPARE(e->layoutData->items[10].num_glyphs, ushort(2)); // Thai: Thai character followed by superscript "a" which is of inherited type + QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(15)); // Thai: The ZWJ and ZWNJ characters are inherited, so should be part of the thai script + QCOMPARE(e->layoutData->items[1].num_glyphs, ushort(1)); // Han: Kanji for tree + QCOMPARE(e->layoutData->items[2].num_glyphs, ushort(2)); // Thai: Thai character followed by superscript "a" which is of inherited type //A quick sanity check - check all the characters are individual clusters unsigned short *logClusters = e->layoutData->logClustersPtr; - for (int i = 0; i < 7; i++) + for (int i = 0; i <= 14; i++) QCOMPARE(logClusters[i], ushort(i)); - for (int i = 0; i < 10; i++) - QCOMPARE(logClusters[i+7], ushort(0)); + QCOMPARE(logClusters[15], ushort(0)); + QCOMPARE(logClusters[16], ushort(0)); +#ifndef Q_OS_MAC + // ### Result differs for HarfBuzz-NG QCOMPARE(logClusters[17], ushort(1)); +#endif // A thai implementation could either remove the ZWJ and ZWNJ characters, or hide them. // The current implementation hides them, so we test for that. // The only characters that we should be hiding are the ZWJ and ZWNJ characters in position 1 and 3. const QGlyphLayout glyphLayout = e->layoutData->glyphLayout; for (int i = 0; i < 18; i++) { +#ifdef Q_OS_MAC + // ### Result differs for HarfBuzz-NG + if (i == 17) + QCOMPARE(glyphLayout.advances[i].toInt(), 0); + else +#endif if (i == 1 || i == 3) QCOMPARE(glyphLayout.advances[i].toInt(), 0); else diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index e589d520cb..122ac63034 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -331,8 +331,8 @@ void tst_QTcpSocket::initTestCase_data() qDebug() << QtNetworkSettings::serverName(); QTest::newRow("WithoutProxy") << false << 0 << false; - QTest::newRow("WithSocks5Proxy") << true << int(Socks5Proxy) << false; - QTest::newRow("WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic) << false; + //QTest::newRow("WithSocks5Proxy") << true << int(Socks5Proxy) << false; ### temporarily disabled, QTBUG-38385 + //QTest::newRow("WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic) << false; ### temporarily disabled, QTBUG-38385 QTest::newRow("WithHttpProxy") << true << int(HttpProxy) << false; QTest::newRow("WithHttpProxyBasicAuth") << true << int(HttpProxy | AuthBasic) << false; @@ -340,8 +340,8 @@ void tst_QTcpSocket::initTestCase_data() #ifndef QT_NO_SSL QTest::newRow("WithoutProxy SSL") << false << 0 << true; - QTest::newRow("WithSocks5Proxy SSL") << true << int(Socks5Proxy) << true; - QTest::newRow("WithSocks5AuthProxy SSL") << true << int(Socks5Proxy | AuthBasic) << true; + //QTest::newRow("WithSocks5Proxy SSL") << true << int(Socks5Proxy) << true; ### temporarily disabled, QTBUG-38385 + //QTest::newRow("WithSocks5AuthProxy SSL") << true << int(Socks5Proxy | AuthBasic) << true; ### temporarily disabled, QTBUG-38385 QTest::newRow("WithHttpProxy SSL") << true << int(HttpProxy) << true; QTest::newRow("WithHttpProxyBasicAuth SSL") << true << int(HttpProxy | AuthBasic) << true; diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index baaf21e6bb..30a9e19138 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -273,10 +273,12 @@ void tst_QSslSocket::initTestCase_data() void tst_QSslSocket::initTestCase() { +#ifndef QT_NO_SSL qDebug("Using SSL library %s (%ld)", qPrintable(QSslSocket::sslLibraryVersionString()), QSslSocket::sslLibraryVersionNumber()); QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); +#endif } void tst_QSslSocket::init() diff --git a/tests/auto/opengl/qgl/tst_qgl.cpp b/tests/auto/opengl/qgl/tst_qgl.cpp index 02f32adf57..71243339aa 100644 --- a/tests/auto/opengl/qgl/tst_qgl.cpp +++ b/tests/auto/opengl/qgl/tst_qgl.cpp @@ -754,7 +754,7 @@ void tst_QGL::openGLVersionCheck() #elif defined(QT_OPENGL_ES_2) QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0); #else - if (QOpenGLContext::currentContext()->isES()) + if (QOpenGLContext::currentContext()->isOpenGLES()) QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0); else QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_1); @@ -1553,7 +1553,7 @@ void tst_QGL::fboFormat() #ifdef QT_OPENGL_ES_2 GL_RGBA; #else - QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL ? GL_RGBA : GL_RGBA8; + QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL ? GL_RGBA : GL_RGBA8; #endif QCOMPARE(int(format1.internalTextureFormat()), expectedFormat); @@ -1630,7 +1630,7 @@ void tst_QGL::fboFormat() #ifdef QT_OPENGL_ES_2 GL_RGBA #else - QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL ? GL_RGBA : GL_RGBA8 + QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL ? GL_RGBA : GL_RGBA8 #endif ); QVERIFY(!(format1c == format3c)); @@ -1643,7 +1643,7 @@ void tst_QGL::fboFormat() #ifdef QT_OPENGL_ES_2 GL_RGBA #else - QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL ? GL_RGBA : GL_RGBA8 + QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL ? GL_RGBA : GL_RGBA8 #endif ); QVERIFY(!(format1c == format4c)); @@ -2420,10 +2420,10 @@ void tst_QGL::extensions() QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Shaders)); QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Buffers)); QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Multisample)); - QVERIFY(!ctx->isES() || allFeatures.testFlag(QOpenGLFunctions::Framebuffers)); + QVERIFY(!ctx->isOpenGLES() || allFeatures.testFlag(QOpenGLFunctions::Framebuffers)); QVERIFY(allFeatures.testFlag(QOpenGLFunctions::NPOTTextures) && allFeatures.testFlag(QOpenGLFunctions::NPOTTextureRepeat)); - if (ctx->isES()) { + if (ctx->isOpenGLES()) { QVERIFY(!allFeatures.testFlag(QOpenGLFunctions::FixedFunctionPipeline)); QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Framebuffers)); } diff --git a/tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp b/tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp index 915f503b3f..a8a9deb25f 100644 --- a/tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp +++ b/tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp @@ -207,6 +207,10 @@ void tst_QGLBuffer::bufferSharing() QSKIP("Unreproducible timeout on Windows (MSVC/MinGW) CI bots"); #endif +#if defined(Q_OS_QNX) + QSKIP("Crashes on QNX when destroying the second QGLWidget (see QTBUG-38275)"); +#endif + QGLWidget *w1 = new QGLWidget(); w1->makeCurrent(); diff --git a/tests/auto/opengl/qglfunctions/tst_qglfunctions.cpp b/tests/auto/opengl/qglfunctions/tst_qglfunctions.cpp index 4e0375171a..a465afef21 100644 --- a/tests/auto/opengl/qglfunctions/tst_qglfunctions.cpp +++ b/tests/auto/opengl/qglfunctions/tst_qglfunctions.cpp @@ -96,7 +96,7 @@ void tst_QGLFunctions::features() funcs.initializeGLFunctions(); // Validate the features against what we expect for this platform. - if (QOpenGLContext::currentContext()->isES()) { + if (QOpenGLContext::currentContext()->isOpenGLES()) { #if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2) QGLFunctions::OpenGLFeatures allFeatures = (QGLFunctions::Multitexture | diff --git a/tests/auto/opengl/qglthreads/tst_qglthreads.cpp b/tests/auto/opengl/qglthreads/tst_qglthreads.cpp index e190af31e4..25057ba2a0 100644 --- a/tests/auto/opengl/qglthreads/tst_qglthreads.cpp +++ b/tests/auto/opengl/qglthreads/tst_qglthreads.cpp @@ -345,7 +345,7 @@ void renderAScene(int w, int h) { QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - if (QOpenGLContext::currentContext()->isES()) { + if (QOpenGLContext::currentContext()->isOpenGLES()) { Q_UNUSED(w); Q_UNUSED(h); QGLShaderProgram program; diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index fcc5581bea..1cc79f643a 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -3283,7 +3283,7 @@ void tst_QAccessibility::comboBoxTest() QVERIFY(!combo.view()->isVisible()); QVERIFY(iface->actionInterface()); - QCOMPARE(iface->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction()); + QCOMPARE(iface->actionInterface()->actionNames(), QStringList() << QAccessibleActionInterface::showMenuAction() << QAccessibleActionInterface::pressAction()); iface->actionInterface()->doAction(QAccessibleActionInterface::showMenuAction()); QTRY_VERIFY(combo.view()->isVisible()); diff --git a/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp b/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp index 9763e3e7e6..847453b3ed 100644 --- a/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp +++ b/tests/auto/sql/kernel/qsqlerror/tst_qsqlerror.cpp @@ -102,6 +102,7 @@ void tst_QSqlError::construction() QCOMPARE(obj1.databaseText(), QString("databasetext")); QCOMPARE(obj1.type(), QSqlError::UnknownError); QCOMPARE(obj1.number(), 123); + QCOMPARE(obj1.nativeErrorCode(), QStringLiteral("123")); QVERIFY(obj1.isValid()); QSqlError obj2(obj1); @@ -109,6 +110,7 @@ void tst_QSqlError::construction() QCOMPARE(obj2.databaseText(), obj1.databaseText()); QCOMPARE(obj2.type(), obj1.type()); QCOMPARE(obj2.number(), obj1.number()); + QCOMPARE(obj2.nativeErrorCode(), obj1.nativeErrorCode()); QVERIFY(obj2.isValid()); QSqlError obj3 = obj2; @@ -116,10 +118,16 @@ void tst_QSqlError::construction() QCOMPARE(obj3.databaseText(), obj2.databaseText()); QCOMPARE(obj3.type(), obj2.type()); QCOMPARE(obj3.number(), obj2.number()); + QCOMPARE(obj3.nativeErrorCode(), obj2.nativeErrorCode()); QVERIFY(obj3.isValid()); QSqlError obj4; QVERIFY(!obj4.isValid()); + QCOMPARE(obj4.driverText(), QString()); + QCOMPARE(obj4.databaseText(), QString()); + QCOMPARE(obj4.type(), QSqlError::NoError); + QCOMPARE(obj4.number(), -1); + QCOMPARE(obj4.nativeErrorCode(), QString()); QSqlError obj5(QStringLiteral("drivertext"), QStringLiteral("databasetext"), QSqlError::UnknownError, QStringLiteral("123")); @@ -138,6 +146,16 @@ void tst_QSqlError::construction() QCOMPARE(obj6.number(), 0); QCOMPARE(obj6.nativeErrorCode(), QStringLiteral("Err123")); QVERIFY(obj6.isValid()); + + // Default constructed object as constructed before Qt 5.3 + QSqlError obj7(QString(), QString(), QSqlError::NoError, -1); + QVERIFY(!obj7.isValid()); + QCOMPARE(obj7.driverText(), QString()); + QCOMPARE(obj7.databaseText(), QString()); + QCOMPARE(obj7.type(), QSqlError::NoError); + QCOMPARE(obj7.number(), -1); + QCOMPARE(obj7.nativeErrorCode(), QString()); + } void tst_QSqlError::operators() diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp index 55cb67eed9..824f042ffc 100644 --- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp @@ -195,6 +195,9 @@ private slots: void task_233829_data() { generic_data("QPSQL"); } void task_233829(); + void QTBUG_12477_data() { generic_data("QPSQL"); } + void QTBUG_12477(); + void sqlServerReturn0_data() { generic_data(); } void sqlServerReturn0(); @@ -1247,6 +1250,26 @@ void tst_QSqlQuery::seek() QVERIFY( q.seek( 0 ) ); QCOMPARE( q.at(), 0 ); QCOMPARE( q.value( 0 ).toInt(), 1 ); + + QVERIFY(!q.seek(QSql::BeforeFirstRow)); + QCOMPARE(q.at(), int(QSql::BeforeFirstRow)); + QVERIFY(q.seek(1, true)); + QCOMPARE(q.at(), 0); + QCOMPARE(q.value(0).toInt(), 1); + + qint32 count = 1; + while (q.next()) ++count; + + QCOMPARE(q.at(), int(QSql::AfterLastRow)); + + if (!q.isForwardOnly()) { + QVERIFY(q.seek(-1, true)); + QCOMPARE(q.at(), count - 1); + QCOMPARE(q.value(0).toInt(), count); + } else { + QVERIFY(!q.seek(-1, true)); + QCOMPARE(q.at(), int(QSql::AfterLastRow)); + } } void tst_QSqlQuery::seekForwardOnlyQuery() @@ -2992,6 +3015,47 @@ void tst_QSqlQuery::task_233829() QVERIFY_SQL(q,exec()); } +void tst_QSqlQuery::QTBUG_12477() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + if (!db.driverName().startsWith("QPSQL")) + QSKIP("PostgreSQL specific test"); + + QSqlQuery q(db); + QVERIFY_SQL(q, exec("SELECT 1::bit, '10101010000111101101'::varbit, " + "'10101111011'::varbit(15), '22222.20'::numeric(16,2), " + "'333333'::numeric(18), '444444'::numeric")); + QVERIFY_SQL(q, next()); + QSqlRecord r = q.record(); + QSqlField f; + + f = r.field(0); + QCOMPARE(f.length(), 1); + QCOMPARE(f.precision(), -1); + + f = r.field(1); + QCOMPARE(f.length(), -1); + QCOMPARE(f.precision(), -1); + + f = r.field(2); + QCOMPARE(f.length(), 15); + QCOMPARE(f.precision(), -1); + + f = r.field(3); + QCOMPARE(f.length(), 16); + QCOMPARE(f.precision(), 2); + + f = r.field(4); + QCOMPARE(f.length(), 18); + QCOMPARE(f.precision(), 0); + + f = r.field(5); + QCOMPARE(f.length(), -1); + QCOMPARE(f.precision(), -1); +} + void tst_QSqlQuery::sqlServerReturn0() { QFETCH( QString, dbName ); diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp index d360a646f1..047df0d3f2 100644 --- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -72,6 +73,7 @@ #include #if defined(Q_OS_UNIX) +#include // for pathconf() on OS X #ifdef QT_BUILD_INTERNAL QT_BEGIN_NAMESPACE extern Q_GUI_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0); @@ -79,6 +81,19 @@ QT_END_NAMESPACE #endif #endif +static inline bool isCaseSensitiveFileSystem(const QString &path) +{ + Q_UNUSED(path) +#if defined(Q_OS_MAC) + return pathconf(QFile::encodeName(path).constData(), _PC_CASE_SENSITIVE); +#elif defined(Q_OS_WIN) + return false; +#else + return true; +#endif +} + + class QNonNativeFileDialog : public QFileDialog { Q_OBJECT @@ -130,6 +145,7 @@ private slots: void selectFile_data(); void selectFile(); void selectFiles(); + void selectFileWrongCaseSaveAs(); void selectFilter(); void viewMode(); void proxymodel(); @@ -147,6 +163,7 @@ private slots: void clearLineEdit(); void enableChooseButton(); void widgetlessNativeDialog(); + void selectedFilesWithoutWidgets(); void trailingDotsAndSpaces(); #ifdef Q_OS_UNIX #ifdef QT_BUILD_INTERNAL @@ -857,36 +874,59 @@ void tst_QFiledialog::selectFile() { QFETCH(QString, file); QFETCH(int, count); - QNonNativeFileDialog fd; - QFileSystemModel *model = fd.findChild("qt_filesystem_model"); + QScopedPointer fd(new QNonNativeFileDialog); + QFileSystemModel *model = fd->findChild("qt_filesystem_model"); QVERIFY(model); - fd.setDirectory(QDir::currentPath()); + fd->setDirectory(QDir::currentPath()); // default value - QCOMPARE(fd.selectedFiles().count(), 1); + QCOMPARE(fd->selectedFiles().count(), 1); - QTemporaryFile tempFile(QDir::tempPath() + "/aXXXXXX"); - bool inTemp = (file == "temp"); - if (inTemp) { - tempFile.open(); - file = tempFile.fileName(); + QScopedPointer tempFile; + if (file == QLatin1String("temp")) { + tempFile.reset(new QTemporaryFile(QDir::tempPath() + QStringLiteral("/aXXXXXX"))); + QVERIFY(tempFile->open()); + file = tempFile->fileName(); } - fd.selectFile(file); - QCOMPARE(fd.selectedFiles().count(), count); - if (inTemp) { - QCOMPARE(model->index(fd.directory().path()), model->index(QDir::tempPath())); + fd->selectFile(file); + QCOMPARE(fd->selectedFiles().count(), count); + if (tempFile.isNull()) { + QCOMPARE(model->index(fd->directory().path()), model->index(QDir::currentPath())); } else { - QCOMPARE(model->index(fd.directory().path()), model->index(QDir::currentPath())); + QCOMPARE(model->index(fd->directory().path()), model->index(QDir::tempPath())); } + fd.reset(); // Ensure the file dialog let's go of the temporary file for "temp". +} + +void tst_QFiledialog::selectFileWrongCaseSaveAs() +{ + const QString home = QDir::homePath(); + if (isCaseSensitiveFileSystem(home)) + QSKIP("This test is intended for case-insensitive file systems only."); + // QTBUG-38162: when passing a wrongly capitalized path to selectFile() + // on a case-insensitive file system, the line edit should only + // contain the file name ("c:\PRogram files\foo.txt" -> "foo.txt"). + const QString fileName = QStringLiteral("foo.txt"); + const QString path = home + QLatin1Char('/') + fileName; + QString wrongCasePath = path; + for (int c = 0; c < wrongCasePath.size(); c += 2) + wrongCasePath[c] = wrongCasePath.at(c).isLower() ? wrongCasePath.at(c).toUpper() : wrongCasePath.at(c).toLower(); + QNonNativeFileDialog fd(0, "QTBUG-38162", wrongCasePath); + fd.setAcceptMode(QFileDialog::AcceptSave); + fd.selectFile(wrongCasePath); + const QLineEdit *lineEdit = fd.findChild("fileNameEdit"); + QVERIFY(lineEdit); + QCOMPARE(lineEdit->text().compare(fileName, Qt::CaseInsensitive), 0); } void tst_QFiledialog::selectFiles() { - QNonNativeFileDialog fd; - fd.setViewMode(QFileDialog::List); QTemporaryDir tempDir; QVERIFY(tempDir.isValid()); const QString tempPath = tempDir.path(); + { + QNonNativeFileDialog fd; + fd.setViewMode(QFileDialog::List); fd.setDirectory(tempPath); QSignalSpy spyCurrentChanged(&fd, SIGNAL(currentChanged(QString))); QSignalSpy spyDirectoryEntered(&fd, SIGNAL(directoryEntered(QString))); @@ -931,17 +971,20 @@ void tst_QFiledialog::selectFiles() QCOMPARE(spyFilesSelected.count(), 0); QCOMPARE(spyFilterSelected.count(), 0); - //If the selection is invalid then we fill the line edit but without the / - QNonNativeFileDialog * dialog = new QNonNativeFileDialog( 0, "Save" ); - dialog->setFileMode( QFileDialog::AnyFile ); - dialog->setAcceptMode( QFileDialog::AcceptSave ); - dialog->selectFile(tempPath + QStringLiteral("/blah")); - dialog->show(); - QVERIFY(QTest::qWaitForWindowExposed(dialog)); - QLineEdit *lineEdit = dialog->findChild("fileNameEdit"); - QVERIFY(lineEdit); - QCOMPARE(lineEdit->text(),QLatin1String("blah")); - delete dialog; + } + + { + //If the selection is invalid then we fill the line edit but without the / + QNonNativeFileDialog dialog( 0, "Save" ); + dialog.setFileMode( QFileDialog::AnyFile ); + dialog.setAcceptMode( QFileDialog::AcceptSave ); + dialog.selectFile(tempPath + QStringLiteral("/blah")); + dialog.show(); + QVERIFY(QTest::qWaitForWindowExposed(&dialog)); + QLineEdit *lineEdit = dialog.findChild("fileNameEdit"); + QVERIFY(lineEdit); + QCOMPARE(lineEdit->text(),QLatin1String("blah")); + } } void tst_QFiledialog::viewMode() @@ -1321,6 +1364,14 @@ void tst_QFiledialog::widgetlessNativeDialog() QVERIFY(!button); } +void tst_QFiledialog::selectedFilesWithoutWidgets() +{ + // Test for a crash when widgets are not instantiated yet. + QFileDialog fd; + fd.setAcceptMode(QFileDialog::AcceptOpen); + QVERIFY(fd.selectedFiles().size() >= 0); +} + void tst_QFiledialog::trailingDotsAndSpaces() { #ifndef Q_OS_WIN diff --git a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp index 9e0446388e..3925090465 100644 --- a/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. @@ -476,13 +476,19 @@ void tst_QFileSystemModel::rowCount() void tst_QFileSystemModel::rowsInserted_data() { QTest::addColumn("count"); - QTest::addColumn("assending"); + QTest::addColumn("ascending"); for (int i = 0; i < 4; ++i) { QTest::newRow(QString("Qt::AscendingOrder %1").arg(i).toLocal8Bit().constData()) << i << (int)Qt::AscendingOrder; QTest::newRow(QString("Qt::DescendingOrder %1").arg(i).toLocal8Bit().constData()) << i << (int)Qt::DescendingOrder; } } +static inline QString lastEntry(const QModelIndex &root) +{ + const QAbstractItemModel *model = root.model(); + return model->index(model->rowCount(root) - 1, 0, root).data().toString(); +} + void tst_QFileSystemModel::rowsInserted() { #if defined(Q_OS_WINCE) @@ -492,9 +498,9 @@ void tst_QFileSystemModel::rowsInserted() rowCount(); QModelIndex root = model->index(model->rootPath()); - QFETCH(int, assending); + QFETCH(int, ascending); QFETCH(int, count); - model->sort(0, (Qt::SortOrder)assending); + model->sort(0, (Qt::SortOrder)ascending); QSignalSpy spy0(model, SIGNAL(rowsInserted(QModelIndex,int,int))); QSignalSpy spy1(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); @@ -505,7 +511,6 @@ void tst_QFileSystemModel::rowsInserted() QVERIFY(createFiles(tmp, files, 5)); TRY_WAIT(model->rowCount(root) == oldCount + count); QTRY_COMPARE(model->rowCount(root), oldCount + count); - QTest::qWait(100); // Let the sort settle. int totalRowsInserted = 0; for (int i = 0; i < spy0.count(); ++i) { int start = spy0[i].value(1).toInt(); @@ -513,12 +518,9 @@ void tst_QFileSystemModel::rowsInserted() totalRowsInserted += end - start + 1; } QCOMPARE(totalRowsInserted, count); - if (assending == (Qt::SortOrder)Qt::AscendingOrder) { - QString letter = model->index(model->rowCount(root) - 1, 0, root).data().toString(); - QCOMPARE(letter, QString("j")); - } else { - QCOMPARE(model->index(model->rowCount(root) - 1, 0, root).data().toString(), QString("b")); - } + const QString expected = ascending == Qt::AscendingOrder ? QStringLiteral("j") : QStringLiteral("b"); + QTRY_COMPARE(lastEntry(root), expected); + if (spy0.count() > 0) { if (count == 0) QCOMPARE(spy0.count(), 0); @@ -548,8 +550,8 @@ void tst_QFileSystemModel::rowsRemoved() QModelIndex root = model->index(model->rootPath()); QFETCH(int, count); - QFETCH(int, assending); - model->sort(0, (Qt::SortOrder)assending); + QFETCH(int, ascending); + model->sort(0, (Qt::SortOrder)ascending); QTest::qWait(WAITTIME); QSignalSpy spy0(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); diff --git a/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp b/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp index 4c07b48c00..a932a2e859 100644 --- a/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp +++ b/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp @@ -2605,6 +2605,9 @@ void tst_QWizard::task161658_alignments() void tst_QWizard::task177022_setFixedSize() { +#ifdef Q_OS_BLACKBERRY + QSKIP("Window is forced fullscreen"); +#endif int width = 300; int height = 200; QWizard wiz; @@ -2622,7 +2625,7 @@ void tst_QWizard::task177022_setFixedSize() QCOMPARE(wiz.maximumWidth(), width); QCOMPARE(wiz.maximumHeight(), height); - wiz.show(); + wiz.showNormal(); QVERIFY(QTest::qWaitForWindowExposed(&wiz)); QCOMPARE(wiz.size(), QSize(width, height)); diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp index 5b178903cf..8f57eca0a7 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp @@ -2502,9 +2502,6 @@ void tst_QGraphicsProxyWidget::popup_basic() void tst_QGraphicsProxyWidget::popup_subwidget() { -#ifdef Q_OS_WIN - QSKIP("This test crashes on Windows, QTBUG-33213"); -#endif QGroupBox *groupBox = new QGroupBox; groupBox->setTitle("GroupBox"); groupBox->setCheckable(true); @@ -3183,10 +3180,6 @@ void tst_QGraphicsProxyWidget::actionsContextMenu() void tst_QGraphicsProxyWidget::deleteProxyForChildWidget() { -#if defined(Q_OS_WIN) - QSKIP("This test is crashing on windows, it needs to be fixed. QTBUG-29684"); -#endif - QDialog dialog; dialog.resize(320, 120); dialog.move(80, 40); diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index 83c4582645..daca1d1516 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -1257,7 +1257,7 @@ void tst_QAbstractItemView::task250754_fontChange() tree.setModel(m); tree.setHeaderHidden(true); // The header is (in certain styles) dpi dependent - w.resize(160, 300); // Minimum width for windows with frame on Windows 8 + w.resize(160, 350); // Minimum width for windows with frame on Windows 8 centerOnScreen(&w); moveCursorAway(&w); w.showNormal(); diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index 0579914940..77690cc27a 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -2488,7 +2488,7 @@ void tst_QTreeView::extendedSelection_data() QTest::addColumn("selectedCount"); QTest::newRow("select") << QPoint(10, 10) << 2; - QTest::newRow("unselect") << QPoint(10, 150) << 0; + QTest::newRow("unselect") << QPoint(10, 300) << 0; } void tst_QTreeView::extendedSelection() @@ -2499,7 +2499,7 @@ void tst_QTreeView::extendedSelection() QStandardItemModel model(5, 2); QWidget topLevel; QTreeView view(&topLevel); - view.resize(qMax(mousePressPos.x() * 2, 200), qMax(mousePressPos.y() * 2, 200)); + view.resize(qMax(mousePressPos.x() * 2, 300), qMax(mousePressPos.y() * 2, 350)); view.setModel(&model); view.setSelectionMode(QAbstractItemView::ExtendedSelection); topLevel.show(); diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index 509ccc37b6..abc0129f8b 100644 --- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -2064,7 +2064,7 @@ void tst_QComboBox::itemListPosition() topLevel.move(screen.width() - topLevel.sizeHint().width() - 10, 0); //puts the combo to the top-right corner - topLevel.show(); + topLevel.showNormal(); //wait because the window manager can move the window if there is a right panel QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); @@ -2232,7 +2232,7 @@ void tst_QComboBox::task190205_setModelAdjustToContents() box.move(100, 100); box.setSizeAdjustPolicy(QComboBox::AdjustToContents); box.addItems(initialContent); - box.show(); + box.showNormal(); //wait needed in order to get the combo initial size QTRY_VERIFY(box.isVisible()); @@ -2244,7 +2244,7 @@ void tst_QComboBox::task190205_setModelAdjustToContents() correctBox.move(400, 100); correctBox.addItems(finalContent); - correctBox.show(); + correctBox.showNormal(); QVERIFY(QTest::qWaitForWindowExposed(&box)); QVERIFY(QTest::qWaitForWindowExposed(&correctBox)); @@ -2266,7 +2266,7 @@ void tst_QComboBox::task248169_popupWithMinimalSize() comboBox.setGeometry(desktopSize.width() - (desktopSize.width() / 4), (desktopSize.width() / 4), (desktopSize.width() / 2), (desktopSize.width() / 4)); - comboBox.show(); + comboBox.showNormal(); QVERIFY(QTest::qWaitForWindowExposed(&comboBox)); QTRY_VERIFY(comboBox.isVisible()); comboBox.showPopup(); @@ -2274,7 +2274,7 @@ void tst_QComboBox::task248169_popupWithMinimalSize() QTest::qWaitForWindowExposed(comboBox.view()); QTRY_VERIFY(comboBox.view()->isVisible()); -#ifdef QT_BUILD_INTERNAL +#if defined QT_BUILD_INTERNAL && !defined Q_OS_BLACKBERRY QFrame *container = comboBox.findChild(); QVERIFY(container); QTRY_VERIFY(desktop.screenGeometry(container).contains(container->geometry())); @@ -2609,7 +2609,7 @@ void tst_QComboBox::keyBoardNavigationWithMouse() for (int i = 0; i < 80; i++) combo.addItem( QString::number(i)); - combo.show(); + combo.showNormal(); centerCursor(&combo); // QTBUG-33973, cursor needs to be within view from start on Mac. QApplication::setActiveWindow(&combo); QVERIFY(QTest::qWaitForWindowActive(&combo)); @@ -2629,7 +2629,7 @@ void tst_QComboBox::keyBoardNavigationWithMouse() QCOMPARE(combo.currentText(), QLatin1String("0")); // When calling cursor function, Windows CE responds with: This function is not supported on this system. -#ifndef Q_OS_WINCE +#if !defined Q_OS_WINCE && !defined Q_OS_QNX // Force cursor movement to prevent QCursor::setPos() from returning prematurely on QPA: centerCursor(combo.view()); QTest::qWait(200); diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index 6551a88232..095fa3347d 100644 --- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -801,13 +801,16 @@ void tst_QDockWidget::task237438_setFloatingCrash() void tst_QDockWidget::task248604_infiniteResize() { +#if defined Q_OS_BLACKBERRY + QSKIP("Top level window is stretched to fullscreen"); +#endif QDockWidget d; QTabWidget *t = new QTabWidget; t->addTab(new QWidget, "Foo"); d.setWidget(t); d.setContentsMargins(2, 2, 2, 2); d.setMinimumSize(320, 240); - d.show(); + d.showNormal(); QTest::qWait(400); QCOMPARE(d.size(), QSize(320, 240)); } diff --git a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp index 6784ee477b..6b763f5a4c 100644 --- a/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp +++ b/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp @@ -825,6 +825,8 @@ void tst_QDoubleSpinBox::editingFinished() QCOMPARE(editingFinishedSpy1.count(), 4); QCOMPARE(editingFinishedSpy2.count(), 4); + testFocusWidget->show(); // On BlackBerry this is our root window we need to show it again + // otherwise subsequent tests will fail } void tst_QDoubleSpinBox::removeAll() diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 077e1aa1df..36f14cb1ba 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -1322,7 +1322,7 @@ void tst_QLineEdit::undo_keypressevents_data() // unselect any current selection keys.addKeyClick(Qt::Key_Right); -#ifdef Q_OS_WIN //Mac has a specialcase to handle jumping to the end of a selection +#if defined Q_OS_WIN || defined Q_OS_QNX //Windows and QNX do not jump to the beginning of the selection keys.addKeyClick(Qt::Key_Left); #endif @@ -3206,7 +3206,7 @@ void tst_QLineEdit::leftKeyOnSelectedText() QCOMPARE(testWidget->cursorPosition(), 2); QCOMPARE(testWidget->selectedText(), QString("23")); QTest::keyClick(testWidget, Qt::Key_Left); -#ifdef Q_OS_WIN +#if defined Q_OS_WIN || defined Q_OS_QNX QCOMPARE(testWidget->cursorPosition(), 1); #else // Selection is cleared ands cursor remains at position 2. diff --git a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp index ba9652a170..59021108a2 100644 --- a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp +++ b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp @@ -1007,7 +1007,7 @@ void tst_QMdiArea::activeSubWindow() qApp->setActiveWindow(&mainWindow); QCOMPARE(mdiArea->activeSubWindow(), subWindow); -#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN) +#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN) && !defined(Q_OS_QNX) qApp->setActiveWindow(0); QVERIFY(!mdiArea->activeSubWindow()); #endif @@ -1088,7 +1088,7 @@ void tst_QMdiArea::currentSubWindow() QVERIFY(mdiArea.activeSubWindow()); QVERIFY(mdiArea.currentSubWindow()); -#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN) +#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN) && !defined(Q_OS_QNX) qApp->setActiveWindow(0); QVERIFY(!mdiArea.activeSubWindow()); QVERIFY(mdiArea.currentSubWindow()); @@ -1701,7 +1701,7 @@ void tst_QMdiArea::tileSubWindows() qApp->processEvents(); QTRY_COMPARE(workspace.size(), QSize(350, 150)); - const QSize minSize(300, 100); + const QSize minSize(600, 130); foreach (QMdiSubWindow *subWindow, workspace.subWindowList()) subWindow->setMinimumSize(minSize); @@ -1908,6 +1908,9 @@ void tst_QMdiArea::dontMaximizeSubWindowOnActivation() for (int i = 0; i < 5; ++i) { QMdiSubWindow *window = mdiArea.addSubWindow(new QWidget); window->show(); +#if defined Q_OS_QNX + QEXPECT_FAIL("", "QTBUG-38231", Abort); +#endif QVERIFY(window->isMaximized()); qApp->processEvents(); } @@ -2598,7 +2601,7 @@ void tst_QMdiArea::nativeSubWindows() if (platformName != QLatin1String("xcb") && platformName != QLatin1String("windows")) QSKIP(qPrintable(QString::fromLatin1("nativeSubWindows() does not work on this platform (%1).").arg(platformName))); #if defined(Q_OS_WIN) && !defined(QT_NO_OPENGL) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) + if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) QSKIP("nativeSubWindows() does not work with ANGLE on Windows, QTBUG-28545."); #endif { // Add native widgets after show. diff --git a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp index 268638a504..ffc3e3b67d 100644 --- a/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp +++ b/tests/auto/widgets/widgets/qmdisubwindow/tst_qmdisubwindow.cpp @@ -206,6 +206,7 @@ private slots: void task_233197(); void task_226929(); void styleChange(); + void testFullScreenState(); }; void tst_QMdiSubWindow::initTestCase() @@ -2007,6 +2008,19 @@ void tst_QMdiSubWindow::styleChange() QCOMPARE(spy.count(), 0); } +void tst_QMdiSubWindow::testFullScreenState() +{ + QMdiArea mdiArea; + mdiArea.showMaximized(); + + QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget); + subWindow->setGeometry(0, 0, 300, 300); + subWindow->showFullScreen(); // QMdiSubWindow does not support the fullscreen state. This call + // should be equivalent to setVisible(true) (and not showNormal()) + QVERIFY(QTest::qWaitForWindowExposed(&mdiArea)); + QCOMPARE(subWindow->size(), QSize(300, 300)); +} + QTEST_MAIN(tst_QMdiSubWindow) #include "tst_qmdisubwindow.moc" diff --git a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp index 345b8d82ad..06dd623368 100644 --- a/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp +++ b/tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp @@ -679,7 +679,8 @@ void tst_QTabBar::tabBarClicked() QCOMPARE(doubleClickSpy.count(), 0); QTest::mouseDClick(&tabBar, button, 0, tabPos); - QCOMPARE(clickSpy.count(), 0); + QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), 0); QCOMPARE(doubleClickSpy.count(), 1); QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), 0); @@ -691,7 +692,8 @@ void tst_QTabBar::tabBarClicked() QCOMPARE(doubleClickSpy.count(), 0); QTest::mouseDClick(&tabBar, button, 0, barPos); - QCOMPARE(clickSpy.count(), 0); + QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), -1); QCOMPARE(doubleClickSpy.count(), 1); QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), -1); diff --git a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp index df11ea9b14..90af617e87 100644 --- a/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp +++ b/tests/auto/widgets/widgets/qtabwidget/tst_qtabwidget.cpp @@ -690,7 +690,8 @@ void tst_QTabWidget::tabBarClicked() QCOMPARE(doubleClickSpy.count(), 0); QTest::mouseDClick(&tabBar, button, 0, tabPos); - QCOMPARE(clickSpy.count(), 0); + QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), 0); QCOMPARE(doubleClickSpy.count(), 1); QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), 0); @@ -702,7 +703,8 @@ void tst_QTabWidget::tabBarClicked() QCOMPARE(doubleClickSpy.count(), 0); QTest::mouseDClick(&tabBar, button, 0, barPos); - QCOMPARE(clickSpy.count(), 0); + QCOMPARE(clickSpy.count(), 1); + QCOMPARE(clickSpy.takeFirst().takeFirst().toInt(), -1); QCOMPARE(doubleClickSpy.count(), 1); QCOMPARE(doubleClickSpy.takeFirst().takeFirst().toInt(), -1); diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index a43737fdaf..62243178e7 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -164,6 +164,7 @@ Configure::Configure(int& argc, char** argv) dictionary[ "GUI" ] = "yes"; dictionary[ "RTTI" ] = "yes"; dictionary[ "STRIP" ] = "yes"; + dictionary[ "SEPARATE_DEBUG_INFO" ] = "no"; dictionary[ "SSE2" ] = "auto"; dictionary[ "SSE3" ] = "auto"; dictionary[ "SSSE3" ] = "auto"; @@ -445,6 +446,10 @@ void Configure::parseCmdLine() dictionary[ "BUILDALL" ] = "yes"; else if (configCmdLine.at(i) == "-force-debug-info") dictionary[ "FORCEDEBUGINFO" ] = "yes"; + else if (configCmdLine.at(i) == "-no-separate-debug-info") + dictionary[ "SEPARATE_DEBUG_INFO" ] = "no"; + else if (configCmdLine.at(i) == "-separate-debug-info") + dictionary[ "SEPARATE_DEBUG_INFO" ] = "yes"; else if (configCmdLine.at(i) == "-compile-examples") { dictionary[ "COMPILE_EXAMPLES" ] = "yes"; @@ -1765,7 +1770,8 @@ bool Configure::displayHelp() desc("BUILD", "debug", "-debug", "Compile and link Qt with debugging turned on."); desc("BUILDALL", "yes", "-debug-and-release", "Compile and link two Qt libraries, with and without debugging turned on.\n"); - desc("FORCEDEBUGINFO", "yes","-force-debug-info", "Create symbol files for release builds.\n"); + desc("FORCEDEBUGINFO", "yes","-force-debug-info", "Create symbol files for release builds."); + desc("SEPARATE_DEBUG_INFO", "yes","-separate-debug-info", "Strip debug information into a separate file.\n"); desc("BUILDDEV", "yes", "-developer-build", "Compile and link Qt with Qt developer options (including auto-tests exporting)\n"); @@ -2165,6 +2171,9 @@ bool Configure::checkAvailability(const QString &part) if (part == "STYLE_WINDOWSXP") available = (platform() == WINDOWS) && findFile("uxtheme.h"); + else if (part == "OBJCOPY") + available = tryCompileProject("unix/objcopy"); + else if (part == "ZLIB") available = findFile("zlib.h"); @@ -2489,6 +2498,21 @@ bool Configure::verifyConfiguration() dictionary["C++11"] = "auto"; } + if (dictionary["SEPARATE_DEBUG_INFO"] == "yes") { + if (dictionary[ "SHARED" ] == "no") { + cout << "ERROR: -separate-debug-info is incompatible with -static" << endl << endl; + dictionary[ "DONE" ] = "error"; + } else if (dictionary[ "BUILD" ] != "debug" + && dictionary[ "BUILDALL" ] == "no" + && dictionary[ "FORCEDEBUGINFO" ] == "no") { + cout << "ERROR: -separate-debug-info needs -debug, -debug-and-release, or -force-debug-info" << endl << endl; + dictionary[ "DONE" ] = "error"; + } else if (dictionary["SEPARATE_DEBUG_INFO"] == "yes" && !checkAvailability("OBJCOPY")) { + cout << "ERROR: -separate-debug-info was requested but this binutils does not support it." << endl; + dictionary[ "DONE" ] = "error"; + } + } + if (dictionary["SQL_SQLITE_LIB"] == "no" && dictionary["SQL_SQLITE"] != "no") { cout << "WARNING: Configure could not detect the presence of a system SQLite3 lib." << endl << "Configure will therefore continue with the SQLite3 lib bundled with Qt." << endl; @@ -2752,6 +2776,8 @@ void Configure::generateOutputVars() if (dictionary[ "BUILDALL" ] == "yes") { qtConfig += "build_all"; } + if (dictionary[ "SEPARATE_DEBUG_INFO" ] == "yes") + qtConfig += "separate_debug_info"; if (dictionary[ "FORCEDEBUGINFO" ] == "yes") qmakeConfig += "force_debug_info"; qmakeConfig += dictionary[ "BUILD" ]; @@ -3372,10 +3398,8 @@ void Configure::generateQConfigPri() if (!dictionary["QT_NAMESPACE"].isEmpty()) configStream << "#namespaces" << endl << "QT_NAMESPACE = " << dictionary["QT_NAMESPACE"] << endl; - if (dictionary[ "SHARED" ] == "no") { - configStream << "QT_DEFAULT_QPA_PLUGIN = q" << qpaPlatformName() << endl - << "QT_DEFAULT_PRINTSUPPORTPLUGIN = " << qpaPrintSupportPluginName() << endl; - } + if (dictionary[ "SHARED" ] == "no") + configStream << "QT_DEFAULT_QPA_PLUGIN = q" << qpaPlatformName() << endl; if (!configStream.flush()) dictionary[ "DONE" ] = "error"; @@ -3548,8 +3572,7 @@ void Configure::generateConfigfiles() for (int i = 0; i < qconfigList.count(); ++i) tmpStream << addDefine(qconfigList.at(i)); - tmpStream << "#define QT_QPA_DEFAULT_PLATFORM_NAME \"" << qpaPlatformName() << "\"" << endl - << "#define QT_QPA_DEFAULT_PRINTSUPPORTPLUGIN_NAME \"" << qpaPrintSupportPluginName() << "\"" << endl; + tmpStream<<"#define QT_QPA_DEFAULT_PLATFORM_NAME \"" << qpaPlatformName() << "\""<