diff --git a/config.tests/qpa/eglfs-brcm/eglfs-brcm.pro b/config.tests/qpa/eglfs-brcm/eglfs-brcm.pro index b63c75c070..ce16a3a391 100644 --- a/config.tests/qpa/eglfs-brcm/eglfs-brcm.pro +++ b/config.tests/qpa/eglfs-brcm/eglfs-brcm.pro @@ -4,4 +4,8 @@ CONFIG -= qt INCLUDEPATH += $$QMAKE_INCDIR_EGL -LIBS += -L$$QMAKE_LIBDIR_EGL -lEGL -lGLESv2 -lbcm_host +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +LIBS += -lEGL -lGLESv2 -lbcm_host diff --git a/configure b/configure index 6b59a888d4..7251e8e673 100755 --- a/configure +++ b/configure @@ -728,6 +728,7 @@ CFG_EVENTFD=auto CFG_RPATH=yes CFG_FRAMEWORK=auto CFG_USE_GOLD_LINKER=auto +CFG_ENABLE_NEW_DTAGS=auto DEFINES= INCLUDES= D_FLAGS= @@ -2961,8 +2962,20 @@ if [ -f "$relpath"/LICENSE.PREVIEW.COMMERCIAL ] && [ $COMMERCIAL_USER = "yes" ]; Edition="Preview" EditionString="Technology Preview" elif [ $COMMERCIAL_USER = "yes" ]; then - if test -x "$relpath/bin/licheck"; then - LicheckOutput=`$relpath/bin/licheck $OPT_CONFIRM_LICENSE $relpath $outpath\ + if [ $UNAME_SYSTEM = "Linux" ]; then + if file -L /bin/sh | grep -q "64-bit" ; then + Licheck=licheck64 + else + Licheck=licheck32 + fi + elif [ $UNAME_SYSTEM = "Darwin" ]; then + Licheck=licheck_mac + else + echo >&2 "Host operating system not supported by this edition of Qt." + exit 1 + fi + if [ -x "$relpath/bin/$Licheck" ]; then + LicheckOutput=`$relpath/bin/$Licheck $OPT_CONFIRM_LICENSE $relpath $outpath\ $PLATFORM $XPLATFORM` if [ $? -ne 0 ]; then exit 1 @@ -2973,7 +2986,7 @@ elif [ $COMMERCIAL_USER = "yes" ]; then echo echo "Error: This is the Open Source version of Qt." echo "If you want to use Enterprise features of Qt," - echo "information use the contact form at http://www.qt.io/contact-us" + echo "use the contact form at http://www.qt.io/contact-us" echo "to purchase a license." echo exit 1 @@ -3305,7 +3318,7 @@ if [ "$XPLATFORM_IOS" = "yes" ]; then CFG_RPATH="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 qtwebkit qtwebkit-examples" + CFG_SKIP_MODULES="$CFG_SKIP_MODULES qtdoc qtmacextras qtserialport qtwebkit qtwebkit-examples" CFG_PRECOMPILE="no" # Precompiled headers not supported with multiple -arch arguments # If the user passes -sdk on the command line we build a SDK-specific Qt build. @@ -3442,6 +3455,13 @@ if [ "$CFG_USE_GOLD_LINKER" != "no" ]; then fi fi +# auto-detect --enable-new-dtags support +if linkerSupportsFlag $TEST_COMPILER --enable-new-dtags; then + CFG_ENABLE_NEW_DTAGS=yes +else + CFG_ENABLE_NEW_DTAGS=no +fi + # auto-detect -fstack-protector-strong support (for QNX only currently) if [ "$XPLATFORM_QNX" = "yes" ]; then if compilerSupportsFlag $TEST_COMPILER -fstack-protector-strong; then @@ -5338,6 +5358,14 @@ fi # auto-detect XInput2 support if [ "$CFG_XINPUT2" != "no" ]; then if compileTest x11/xinput2 "XInput2"; then + if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists xi 2>/dev/null; then + QMAKE_LIBXI_VERSION_MAJOR=`$PKG_CONFIG --modversion xi 2>/dev/null | cut -d . -f 1` + QMAKE_LIBXI_VERSION_MINOR=`$PKG_CONFIG --modversion xi 2>/dev/null | cut -d . -f 2` + QMAKE_LIBXI_VERSION_PATCH=`$PKG_CONFIG --modversion xi 2>/dev/null | cut -d . -f 3` + QMakeVar set QMAKE_LIBXI_VERSION_MAJOR "$QMAKE_LIBXI_VERSION_MAJOR" + QMakeVar set QMAKE_LIBXI_VERSION_MINOR "$QMAKE_LIBXI_VERSION_MINOR" + QMakeVar set QMAKE_LIBXI_VERSION_PATCH "$QMAKE_LIBXI_VERSION_PATCH" + fi CFG_XINPUT2=yes CFG_XINPUT=no else @@ -6067,6 +6095,7 @@ fi [ "$CFG_STRIP" = "no" ] && QMAKE_CONFIG="$QMAKE_CONFIG nostrip" [ "$CFG_PRECOMPILE" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG precompile_header" [ "$CFG_USE_GOLD_LINKER" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG use_gold_linker" +[ "$CFG_ENABLE_NEW_DTAGS" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG enable_new_dtags" if [ "$CFG_SEPARATE_DEBUG_INFO" = "yes" ]; then QT_CONFIG="$QT_CONFIG separate_debug_info" fi @@ -6196,11 +6225,7 @@ fi [ '!' -z "$INCLUDES" ] && QMakeVar add INCLUDEPATH "$INCLUDES" [ '!' -z "$L_FLAGS" ] && QMakeVar add LIBS "$L_FLAGS" -if [ "$XPLATFORM_MAC" = "yes" ] && [ "$QT_CROSS_COMPILE" = "no" ]; then - if [ "$CFG_RPATH" = "yes" ]; then - QMAKE_CONFIG="$QMAKE_CONFIG absolute_library_soname" - fi -elif [ -z "`getXQMakeConf 'QMAKE_(LFLAGS_)?RPATH'`" ]; then +if [ -z "`getXQMakeConf 'QMAKE_(LFLAGS_)?RPATH'`" ]; then if [ -n "$RPATH_FLAGS" ]; then echo echo "ERROR: -R cannot be used on this platform as \$QMAKE_LFLAGS_RPATH is" @@ -6758,8 +6783,15 @@ QT_PATCH_VERSION = $QT_PATCH_VERSION QT_LIBINFIX = $QT_LIBINFIX QT_NAMESPACE = $QT_NAMESPACE +QT_EDITION = $Edition EOF +if [ "$Edition" != "OpenSource" ] && [ "$Edition" != "Preview" ]; then + echo "QT_LICHECK = $Licheck" >> "$QTCONFIG.tmp" + echo "QT_RELEASE_DATE = $ReleaseDate" >> "$QTCONFIG.tmp" +fi +echo >> "$QTCONFIG.tmp" + if [ "$CFG_SHARED" = "no" ]; then echo "QT_DEFAULT_QPA_PLUGIN = q$QT_QPA_DEFAULT_PLATFORM" >> "$QTCONFIG.tmp" echo >> "$QTCONFIG.tmp" @@ -6980,6 +7012,7 @@ unset build_mode release echo " Using sanitizer(s)...... $CFG_SANITIZERS" echo " Using C++11 ............ $CFG_CXX11" echo " Using gold linker....... $CFG_USE_GOLD_LINKER" +echo " Using new DTAGS ........ $CFG_ENABLE_NEW_DTAGS" echo " Using PCH .............. $CFG_PRECOMPILE" echo " Target compiler supports:" if [ "$CFG_ARCH" = "i386" -o "$CFG_ARCH" = "x86_64" ]; then diff --git a/dist/changes-5.4.2 b/dist/changes-5.4.2 new file mode 100644 index 0000000000..1a34898011 --- /dev/null +++ b/dist/changes-5.4.2 @@ -0,0 +1,124 @@ +Qt 5.4.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.4.1. Compatibility with Qt +5.4.0 is also retained, except on Windows when using MSVC 2012 or MSVC +2013. See note below. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://doc.qt.io/qt-5.4/ + +The Qt version 5.4 series is binary compatible with the 5.3.x series. +Applications compiled for 5.3 will continue to run with 5.4 with the +exception of on Windows when using MSVC 2012 or MSVC 2013. See note +below. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** +- Restored binary compatibility with Qt 5.3.2 on Windows when using MSVC + 2012 or MSVC 2013. This means that Qt 5.4.1 and 5.4.2 are no longer + binary compatible with Qt 5.4.0 when using either of those compilers. +- [QTBUG-42594] OS X binary package: fixed incorrect linking to libraries in + /opt/local/lib +- EXIF orientation is no longer applied to JPEG images on read. EXIF + orientation on JPEG was introduced in 5.4.0, but due to a bug the most + common EXIF-format (big-endian) was not working until 5.4.1. 5.4.2 restores the + behavior of 5.4.0 and earlier for most EXIF-tagged JPEGs. + EXIF orientation will be an opt-in starting with Qt 5.5. +- On x86 and x86-64 systems with ELF binaries (especially Linux), due to + a new optimization in GCC 5.x in combination with a recent version of + GNU binutils, compiling Qt applications with -fPIE is no longer + enough with GCC 5.x. Applications now need to be compiled with + the -fPIC option if Qt's option "reduce relocations" is active. For + backward compatibility only, Qt accepts the use of -fPIE for GCC 4.x + versions. + Note that Clang is known to generate incompatible code even with -fPIC if + the -flto option is active. + Applications using qmake or cmake >= 2.8.12 as their build system will + adapt automatically. Applications using an older release of cmake in + combination with GCC 5.x need to change their CMakeLists.txt to add + Qt5Core_EXECUTABLE_COMPILE_FLAGS to CMAKE_CXX_FLAGS. In particular, + applications using cmake >= 2.8.9 and < 2.8.11 will continue to build + with the -fPIE option and invoke the special compatibility mode if using + GCC 4.x. + + +**************************************************************************** +* Library * +**************************************************************************** + +QtCore +------ + - [QTBUG-43893] Fixed memory leak in qSetMessagePattern + - [QTBUG-43513] QXmlStreamReader: Correctly parse XML containing NUL bytes + in the input stream + - [QTBUG-43352] QTemporaryDirectory: Properly clean up in case of a failure + - [QTBUG-43827] Fixed regression in QSortFilterProxyModel which crashed when + sorting a tree model + +QtGui +----- + - [QTBUG-44273] Fixed misplacement of outlined text with native text rendering + - [QTBUG-44147] Fixed VNC not working on some VNC servers + - [QTBUG-43850] Fixed crash with multi-threaded font usage + - [QTBUG-43850] Made the old harfbuzz fallback available at runtime + - Improvements to the experimental high-dpi support + - [QTBUG-43318] Better resolution of GLES 3 functions to avoid issues when + deploying on systems with GLES 2.0 only + +QtWidgets +--------- + - [QTBUG-43830] Fixed crash in stylesheets when styling QProgressBar + - [QTBUG-43663] QColorDialog: Don't lose focus while color picking + +QtNetwork +--------- + - [QTBUG-43793] Fixed disconnects of QSSLSocket after starting encryption + +QtPrintSupport +-------------- + - [QTBUG-43124] Fixed QPrinter::{width,height} return values + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +Android +------- + + - [QTBUG-44648] Fixed rendering Chinese text on Android 5 + +Linux/XCB +--------- + + - [QTBUG-45071] Don't crash when resizing windows to bigger than 3840x2160 + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - CMake-based projects using Qt will now always be built with -fPIE, + which fixes function pointer based QObject::connect() on ARM. This + is consistent with qmake + - [Android] Fixed compilation on armv5 with 4.9 toolchain + +qmake +----- + + - [VS] Fixed handling of files that are excluded from build + - [QTBUG-44413][VS] Fixed vcxproj generation for CONFIG-=flat, again + - [QTBUG-44595] Restored Qt 4 behavior of qtLibraryTarget() + - [QTBUG-45118][Windows] Fixed parallel build when using TYPELIBS + - [OS X/iOS] Fixed QMAKE_INFO_PLIST path resolution for shadow builds diff --git a/doc/global/externalsites/qt-webpages.qdoc b/doc/global/externalsites/qt-webpages.qdoc index 057f0259e9..386573e526 100644 --- a/doc/global/externalsites/qt-webpages.qdoc +++ b/doc/global/externalsites/qt-webpages.qdoc @@ -110,3 +110,7 @@ \externalpage http://wiki.qt.io/BlackBerry \title Qt for BlackBerry */ +/*! + \externalpage http://wiki.qt.io/Qt_Multimedia_Backends + \title Qt Multimedia Backends +*/ diff --git a/examples/opengl/legacy/framebufferobject2/framebufferobject2.pro b/examples/opengl/legacy/framebufferobject2/framebufferobject2.pro index e0067cf27f..78fc6b1a63 100644 --- a/examples/opengl/legacy/framebufferobject2/framebufferobject2.pro +++ b/examples/opengl/legacy/framebufferobject2/framebufferobject2.pro @@ -5,11 +5,7 @@ RESOURCES += framebufferobject2.qrc QT += opengl widgets # install -target.path = $$[QT_INSTALL_EXAMPLES]/opengl/framebufferobject2 +target.path = $$[QT_INSTALL_EXAMPLES]/opengl/legacy/framebufferobject2 INSTALLS += target -contains(QT_CONFIG, opengles.) { - contains(QT_CONFIG, angle): \ - warning("Qt was built with ANGLE, which provides only OpenGL ES 2.0 on top of DirectX 9.0c") - error("This example requires Qt to be configured with -opengl desktop") -} +contains(QT_CONFIG, opengles.|angle|dynamicgl):error("This example requires Qt to be configured with -opengl desktop") diff --git a/examples/opengl/legacy/grabber/grabber.pro b/examples/opengl/legacy/grabber/grabber.pro index b8567580f0..1db0e23156 100644 --- a/examples/opengl/legacy/grabber/grabber.pro +++ b/examples/opengl/legacy/grabber/grabber.pro @@ -6,11 +6,7 @@ SOURCES = glwidget.cpp \ QT += opengl widgets # install -target.path = $$[QT_INSTALL_EXAMPLES]/opengl/grabber +target.path = $$[QT_INSTALL_EXAMPLES]/opengl/legacy/grabber INSTALLS += target -contains(QT_CONFIG, opengles.) { - contains(QT_CONFIG, angle): \ - warning("Qt was built with ANGLE, which provides only OpenGL ES 2.0 on top of DirectX 9.0c") - error("This example requires Qt to be configured with -opengl desktop") -} +contains(QT_CONFIG, opengles.|angle|dynamicgl):error("This example requires Qt to be configured with -opengl desktop") diff --git a/examples/opengl/legacy/hellogl/glwidget.cpp b/examples/opengl/legacy/hellogl/glwidget.cpp index 02501cd99e..122f7ddfe1 100644 --- a/examples/opengl/legacy/hellogl/glwidget.cpp +++ b/examples/opengl/legacy/hellogl/glwidget.cpp @@ -128,6 +128,8 @@ void GLWidget::setZRotation(int angle) //! [6] void GLWidget::initializeGL() { + initializeOpenGLFunctions(); + qglClearColor(qtPurple.dark()); logo = new QtLogo(this, 64); @@ -153,7 +155,7 @@ void GLWidget::paintGL() glRotatef(xRot / 16.0, 1.0, 0.0, 0.0); glRotatef(yRot / 16.0, 0.0, 1.0, 0.0); glRotatef(zRot / 16.0, 0.0, 0.0, 1.0); - logo->draw(); + logo->draw(static_cast(this)); } //! [7] diff --git a/examples/opengl/legacy/hellogl/glwidget.h b/examples/opengl/legacy/hellogl/glwidget.h index 994e38e13d..9aca4451df 100644 --- a/examples/opengl/legacy/hellogl/glwidget.h +++ b/examples/opengl/legacy/hellogl/glwidget.h @@ -42,11 +42,12 @@ #define GLWIDGET_H #include +#include class QtLogo; //! [0] -class GLWidget : public QGLWidget +class GLWidget : public QGLWidget, public QOpenGLFunctions_1_1 { Q_OBJECT diff --git a/examples/opengl/legacy/hellogl/hellogl.pro b/examples/opengl/legacy/hellogl/hellogl.pro index 500bd85b3c..c211242fd2 100644 --- a/examples/opengl/legacy/hellogl/hellogl.pro +++ b/examples/opengl/legacy/hellogl/hellogl.pro @@ -11,11 +11,7 @@ SOURCES = glwidget.cpp \ QT += opengl widgets # install -target.path = $$[QT_INSTALL_EXAMPLES]/opengl/hellogl +target.path = $$[QT_INSTALL_EXAMPLES]/opengl/legacy/hellogl INSTALLS += target -contains(QT_CONFIG, opengles.) { - contains(QT_CONFIG, angle): \ - warning("Qt was built with ANGLE, which provides only OpenGL ES 2.0 on top of DirectX 9.0c") - error("This example requires Qt to be configured with -opengl desktop") -} +contains(QT_CONFIG, opengles.|angle):error("This example requires Qt to be configured with -opengl desktop") diff --git a/examples/opengl/legacy/overpainting/glwidget.cpp b/examples/opengl/legacy/overpainting/glwidget.cpp index b41bc31126..52b6c35801 100644 --- a/examples/opengl/legacy/overpainting/glwidget.cpp +++ b/examples/opengl/legacy/overpainting/glwidget.cpp @@ -115,6 +115,8 @@ void GLWidget::setZRotation(int angle) //! [2] void GLWidget::initializeGL() { + initializeOpenGLFunctions(); + glEnable(GL_MULTISAMPLE); logo = new QtLogo(this); @@ -173,7 +175,7 @@ void GLWidget::paintEvent(QPaintEvent *event) glRotatef(yRot / 16.0, 0.0, 1.0, 0.0); glRotatef(zRot / 16.0, 0.0, 0.0, 1.0); - logo->draw(); + logo->draw(static_cast(this)); //! [7] //! [8] diff --git a/examples/opengl/legacy/overpainting/glwidget.h b/examples/opengl/legacy/overpainting/glwidget.h index dd5c0ba9ff..7e62a00170 100644 --- a/examples/opengl/legacy/overpainting/glwidget.h +++ b/examples/opengl/legacy/overpainting/glwidget.h @@ -42,13 +42,14 @@ #define GLWIDGET_H #include +#include #include class Bubble; class QtLogo; //! [0] -class GLWidget : public QGLWidget +class GLWidget : public QGLWidget, public QOpenGLFunctions_1_1 { Q_OBJECT diff --git a/examples/opengl/legacy/overpainting/overpainting.pro b/examples/opengl/legacy/overpainting/overpainting.pro index c1bda7853d..cc46f18889 100644 --- a/examples/opengl/legacy/overpainting/overpainting.pro +++ b/examples/opengl/legacy/overpainting/overpainting.pro @@ -13,11 +13,7 @@ SOURCES = bubble.cpp \ qtlogo.cpp # install -target.path = $$[QT_INSTALL_EXAMPLES]/opengl/overpainting +target.path = $$[QT_INSTALL_EXAMPLES]/opengl/legacy/overpainting INSTALLS += target -contains(QT_CONFIG, opengles.) { - contains(QT_CONFIG, angle): \ - warning("Qt was built with ANGLE, which provides only OpenGL ES 2.0 on top of DirectX 9.0c") - error("This example requires Qt to be configured with -opengl desktop") -} +contains(QT_CONFIG, opengles.|angle):error("This example requires Qt to be configured with -opengl desktop") diff --git a/examples/opengl/legacy/pbuffers/pbuffers.pro b/examples/opengl/legacy/pbuffers/pbuffers.pro index a349e39f68..d779a2a2dc 100644 --- a/examples/opengl/legacy/pbuffers/pbuffers.pro +++ b/examples/opengl/legacy/pbuffers/pbuffers.pro @@ -7,11 +7,7 @@ RESOURCES += pbuffers.qrc QT += opengl widgets # install -target.path = $$[QT_INSTALL_EXAMPLES]/opengl/pbuffers +target.path = $$[QT_INSTALL_EXAMPLES]/opengl/legacy/pbuffers INSTALLS += target -contains(QT_CONFIG, opengles.) { - contains(QT_CONFIG, angle): \ - warning("Qt was built with ANGLE, which provides only OpenGL ES 2.0 on top of DirectX 9.0c") - error("This example requires Qt to be configured with -opengl desktop") -} +contains(QT_CONFIG, opengles.|angle|dynamicgl):error("This example requires Qt to be configured with -opengl desktop") diff --git a/examples/opengl/legacy/pbuffers2/pbuffers2.pro b/examples/opengl/legacy/pbuffers2/pbuffers2.pro index f9dd269eea..2ba40a6f74 100644 --- a/examples/opengl/legacy/pbuffers2/pbuffers2.pro +++ b/examples/opengl/legacy/pbuffers2/pbuffers2.pro @@ -5,11 +5,7 @@ SOURCES += glwidget.cpp main.cpp RESOURCES += pbuffers2.qrc # install -target.path = $$[QT_INSTALL_EXAMPLES]/opengl/pbuffers2 +target.path = $$[QT_INSTALL_EXAMPLES]/opengl/legacy/pbuffers2 INSTALLS += target -contains(QT_CONFIG, opengles.) { - contains(QT_CONFIG, angle): \ - warning("Qt was built with ANGLE, which provides only OpenGL ES 2.0 on top of DirectX 9.0c") - error("This example requires Qt to be configured with -opengl desktop") -} +contains(QT_CONFIG, opengles.|angle|dynamicgl):error("This example requires Qt to be configured with -opengl desktop") diff --git a/examples/opengl/legacy/samplebuffers/samplebuffers.pro b/examples/opengl/legacy/samplebuffers/samplebuffers.pro index b57599aae4..3719f5039d 100644 --- a/examples/opengl/legacy/samplebuffers/samplebuffers.pro +++ b/examples/opengl/legacy/samplebuffers/samplebuffers.pro @@ -4,11 +4,7 @@ SOURCES += glwidget.cpp main.cpp QT += opengl widgets # install -target.path = $$[QT_INSTALL_EXAMPLES]/opengl/samplebuffers +target.path = $$[QT_INSTALL_EXAMPLES]/opengl/legacy/samplebuffers INSTALLS += target -contains(QT_CONFIG, opengles.) { - contains(QT_CONFIG, angle): \ - warning("Qt was built with ANGLE, which provides only OpenGL ES 2.0 on top of DirectX 9.0c") - error("This example requires Qt to be configured with -opengl desktop") -} +contains(QT_CONFIG, opengles.|angle|dynamicgl):error("This example requires Qt to be configured with -opengl desktop") diff --git a/examples/opengl/legacy/shared/qtlogo.cpp b/examples/opengl/legacy/shared/qtlogo.cpp index efe3fb0201..0d960dd4b6 100644 --- a/examples/opengl/legacy/shared/qtlogo.cpp +++ b/examples/opengl/legacy/shared/qtlogo.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -60,7 +61,7 @@ struct Geometry void appendSmooth(const QVector3D &a, const QVector3D &n, int from); void appendFaceted(const QVector3D &a, const QVector3D &n); void finalize(); - void loadArrays() const; + void loadArrays(QOpenGLFunctions_1_1 *functions) const; }; //! [0] @@ -73,7 +74,7 @@ public: void setSmoothing(Smoothing s) { sm = s; } void translate(const QVector3D &t); void rotate(qreal deg, QVector3D axis); - void draw() const; + void draw(QOpenGLFunctions_1_1 *functions) const; void addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n); void addQuad(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d); @@ -96,10 +97,10 @@ static inline void qSetColor(float colorVec[], QColor c) colorVec[3] = c.alphaF(); } -void Geometry::loadArrays() const +void Geometry::loadArrays(QOpenGLFunctions_1_1 *functions) const { - glVertexPointer(3, GL_FLOAT, 0, vertices.constData()); - glNormalPointer(GL_FLOAT, 0, normals.constData()); + functions->glVertexPointer(3, GL_FLOAT, 0, vertices.constData()); + functions->glNormalPointer(GL_FLOAT, 0, normals.constData()); } void Geometry::finalize() @@ -170,15 +171,15 @@ void Patch::translate(const QVector3D &t) } //! [2] -void Patch::draw() const +void Patch::draw(QOpenGLFunctions_1_1 *functions) const { - glPushMatrix(); - glMultMatrixf(mat.constData()); - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, faceColor); + functions->glPushMatrix(); + functions->glMultMatrixf(mat.constData()); + functions->glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, faceColor); const GLushort *indices = geom->faces.constData(); - glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, indices + start); - glPopMatrix(); + functions->glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, indices + start); + functions->glPopMatrix(); } //! [2] @@ -371,17 +372,17 @@ void QtLogo::buildGeometry(int divisions, qreal scale) //! [3] //! [4] -void QtLogo::draw() const +void QtLogo::draw(QOpenGLFunctions_1_1 *functions) const { - geom->loadArrays(); + geom->loadArrays(functions); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); + functions->glEnableClientState(GL_VERTEX_ARRAY); + functions->glEnableClientState(GL_NORMAL_ARRAY); for (int i = 0; i < parts.count(); ++i) - parts[i]->draw(); + parts[i]->draw(functions); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); + functions->glDisableClientState(GL_VERTEX_ARRAY); + functions->glDisableClientState(GL_NORMAL_ARRAY); } //! [4] diff --git a/examples/opengl/legacy/shared/qtlogo.h b/examples/opengl/legacy/shared/qtlogo.h index 562435daed..9bd15a1431 100644 --- a/examples/opengl/legacy/shared/qtlogo.h +++ b/examples/opengl/legacy/shared/qtlogo.h @@ -44,6 +44,7 @@ #include #include +class QOpenGLFunctions_1_1; class Patch; struct Geometry; @@ -54,7 +55,7 @@ public: explicit QtLogo(QObject *parent, int d = 64, qreal s = 1.0); ~QtLogo(); void setColor(QColor c); - void draw() const; + void draw(QOpenGLFunctions_1_1 *functions) const; private: void buildGeometry(int d, qreal s); diff --git a/examples/opengl/qopenglwidget/glwidget.cpp b/examples/opengl/qopenglwidget/glwidget.cpp index f93e667615..df52e3efbf 100644 --- a/examples/opengl/qopenglwidget/glwidget.cpp +++ b/examples/opengl/qopenglwidget/glwidget.cpp @@ -537,14 +537,14 @@ void GLWidget::setTransparent(bool transparent) window()->update(); } -void GLWidget::resizeGL(int w, int h) +void GLWidget::resizeGL(int, int) { if (m_hasButton) { if (!m_btn) { - m_btn = new QPushButton("A widget on top.\nPress me!", this); + m_btn = new QPushButton("A widget on top.\nPress for more widgets.", this); connect(m_btn, &QPushButton::clicked, this, &GLWidget::handleButtonPress); } - m_btn->move(w / 2, h / 2); + m_btn->move(20, 80); } } diff --git a/examples/opengl/qopenglwidget/mainwindow.cpp b/examples/opengl/qopenglwidget/mainwindow.cpp index 6cf1d5d6e2..22111afdcb 100644 --- a/examples/opengl/qopenglwidget/mainwindow.cpp +++ b/examples/opengl/qopenglwidget/mainwindow.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include "glwidget.h" @@ -69,7 +70,7 @@ MainWindow::MainWindow() "and therefore an interval < 16 ms will likely lead to a 60 FPS update rate."); QGroupBox *updateGroupBox = new QGroupBox(this); QCheckBox *timerBased = new QCheckBox("Use timer", this); - timerBased->setChecked(true); + timerBased->setChecked(false); timerBased->setToolTip("Toggles using a timer to trigger update().\n" "When not set, each paintGL() schedules the next update immediately,\n" "expecting the blocking swap to throttle the thread.\n" @@ -87,7 +88,7 @@ MainWindow::MainWindow() slider->setRange(0, 50); slider->setSliderPosition(30); m_timer->setInterval(10); - label->setText("A QOpenGLWidget"); + label->setText("A scrollable QOpenGLWidget"); label->setAlignment(Qt::AlignHCenter); QGroupBox * groupBox = new QGroupBox(this); @@ -96,7 +97,10 @@ MainWindow::MainWindow() m_layout = new QGridLayout(groupBox); - m_layout->addWidget(glwidget,1,0,8,1); + QScrollArea *scrollArea = new QScrollArea; + scrollArea->setWidget(glwidget); + + m_layout->addWidget(scrollArea,1,0,8,1); m_layout->addWidget(label,9,0,1,1); m_layout->addWidget(updateGroupBox, 10, 0, 1, 1); m_layout->addWidget(slider, 11,0,1,1); @@ -134,7 +138,10 @@ MainWindow::MainWindow() connect(timerBased, &QCheckBox::toggled, this, &MainWindow::timerUsageChanged); connect(timerBased, &QCheckBox::toggled, updateInterval, &QWidget::setEnabled); - m_timer->start(); + if (timerBased->isChecked()) + m_timer->start(); + else + updateInterval->setEnabled(false); } void MainWindow::updateIntervalChanged(int value) @@ -170,3 +177,8 @@ void MainWindow::timerUsageChanged(bool enabled) w->update(); } } + +void MainWindow::resizeEvent(QResizeEvent *) +{ + m_glWidgets[0]->setMinimumSize(size() + QSize(128, 128)); +} diff --git a/examples/opengl/qopenglwidget/mainwindow.h b/examples/opengl/qopenglwidget/mainwindow.h index f1b2c51e53..9ad8a01339 100644 --- a/examples/opengl/qopenglwidget/mainwindow.h +++ b/examples/opengl/qopenglwidget/mainwindow.h @@ -56,6 +56,8 @@ public: void addNew(); bool timerEnabled() const { return m_timer->isActive(); } + void resizeEvent(QResizeEvent *); + private slots: void updateIntervalChanged(int value); void timerUsageChanged(bool enabled); diff --git a/examples/touch/fingerpaint/scribblearea.cpp b/examples/touch/fingerpaint/scribblearea.cpp index 469c6b1a70..05598c134c 100644 --- a/examples/touch/fingerpaint/scribblearea.cpp +++ b/examples/touch/fingerpaint/scribblearea.cpp @@ -187,13 +187,14 @@ bool ScribbleArea::event(QEvent *event) foreach (const QTouchEvent::TouchPoint &touchPoint, touchPoints) { switch (touchPoint.state()) { case Qt::TouchPointStationary: - // don't do anything if this touch point hasn't moved + case Qt::TouchPointReleased: + // don't do anything if this touch point hasn't moved or has been released continue; default: { QRectF rect = touchPoint.rect(); if (rect.isEmpty()) { - qreal diameter = MinimumDiameter; + qreal diameter = MaximumDiameter; if (touch->device()->capabilities() & QTouchDevice::Pressure) diameter = MinimumDiameter + (MaximumDiameter - MinimumDiameter) * touchPoint.pressure(); rect.setSize(QSizeF(diameter, diameter)); diff --git a/examples/widgets/doc/images/imagegestures-example.jpg b/examples/widgets/doc/images/imagegestures-example.jpg new file mode 100644 index 0000000000..c8484b4a71 Binary files /dev/null and b/examples/widgets/doc/images/imagegestures-example.jpg differ diff --git a/examples/widgets/doc/src/plugandpaint.qdoc b/examples/widgets/doc/src/plugandpaint.qdoc index 7a8a2cf2fc..a1e26272bc 100644 --- a/examples/widgets/doc/src/plugandpaint.qdoc +++ b/examples/widgets/doc/src/plugandpaint.qdoc @@ -30,8 +30,7 @@ \title Plug & Paint Example \ingroup examples-widgets-tools - \brief The Plug & Paint example demonstrates how to write Qt - applications that can be extended through plugins. + \brief Demonstrates how to extend Qt applications using plugins. \image plugandpaint.png Screenshot of the Plug & Paint example @@ -314,6 +313,9 @@ /*! \example tools/plugandpaintplugins/basictools \title Plug & Paint Basic Tools Example + \brief A plugin providing the basic tools for painting functionality. + + \image plugandpaint.png Screenshot of the Plug & Paint example The Basic Tools example is a static plugin for the \l{tools/plugandpaint}{Plug & Paint} example. It provides a set @@ -499,6 +501,9 @@ /*! \example tools/plugandpaintplugins/extrafilters \title Plug & Paint Extra Filters Example + \brief A plugin providing the extra filters. + + \image plugandpaint.png Screenshot of the Plug & Paint example The Extra Filters example is a plugin for the \l{tools/plugandpaint}{Plug & Paint} example. It provides a set diff --git a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc index 07acef6b4d..2751c64e76 100644 --- a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc +++ b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc @@ -28,10 +28,13 @@ /*! \example gestures/imagegestures \title Image Gestures Example + \brief Demonstrates the use of simple gestures in a widget This example shows how to enable gestures for a widget and use gesture input to perform actions. + \image imagegestures-example.jpg + We use two classes to create the user interface for the application: \c MainWidget and \c ImageWidget. The \c MainWidget class is simply used as a container for the \c ImageWidget class, which we will configure to accept gesture input. Since we diff --git a/examples/widgets/graphicsview/boxes/boxes.pro b/examples/widgets/graphicsview/boxes/boxes.pro index e608b1c845..15d26f02f0 100644 --- a/examples/widgets/graphicsview/boxes/boxes.pro +++ b/examples/widgets/graphicsview/boxes/boxes.pro @@ -1,10 +1,6 @@ QT += opengl widgets -contains(QT_CONFIG, opengles.) { - contains(QT_CONFIG, angle): \ - warning("Qt was built with ANGLE, which provides only OpenGL ES 2.0 on top of DirectX 9.0c") - error("This example requires Qt to be configured with -opengl desktop") -} +contains(QT_CONFIG, opengles.|angle|dynamicgl):error("This example requires Qt to be configured with -opengl desktop") HEADERS += 3rdparty/fbm.h \ glbuffers.h \ diff --git a/examples/widgets/widgets/imageviewer/imageviewer.cpp b/examples/widgets/widgets/imageviewer/imageviewer.cpp index c32f21e7f3..0b8513f090 100644 --- a/examples/widgets/widgets/imageviewer/imageviewer.cpp +++ b/examples/widgets/widgets/imageviewer/imageviewer.cpp @@ -107,7 +107,7 @@ void ImageViewer::open() mimeTypeFilters.sort(); const QStringList picturesLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); QFileDialog dialog(this, tr("Open File"), - picturesLocations.isEmpty() ? QDir::currentPath() : picturesLocations.first()); + picturesLocations.isEmpty() ? QDir::currentPath() : picturesLocations.last()); dialog.setAcceptMode(QFileDialog::AcceptOpen); dialog.setMimeTypeFilters(mimeTypeFilters); dialog.selectMimeTypeFilter("image/jpeg"); diff --git a/examples/widgets/windowcontainer/windowcontainer.cpp b/examples/widgets/windowcontainer/windowcontainer.cpp index 022b6dafc4..a38a10e6f6 100644 --- a/examples/widgets/windowcontainer/windowcontainer.cpp +++ b/examples/widgets/windowcontainer/windowcontainer.cpp @@ -92,10 +92,12 @@ public: } void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE { - m_mouseDown = true; - m_polygon.clear(); - m_polygon.append(e->pos()); - renderLater(); + if (!m_mouseDown) { + m_mouseDown = true; + m_polygon.clear(); + m_polygon.append(e->pos()); + renderLater(); + } } void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE { @@ -106,9 +108,11 @@ public: } void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE { - m_mouseDown = false; - m_polygon.append(e->pos()); - renderLater(); + if (m_mouseDown) { + m_mouseDown = false; + m_polygon.append(e->pos()); + renderLater(); + } } void focusInEvent(QFocusEvent *) Q_DECL_OVERRIDE { diff --git a/mkspecs/common/gcc-base-unix.conf b/mkspecs/common/gcc-base-unix.conf index 29e0521927..f82c8a8430 100644 --- a/mkspecs/common/gcc-base-unix.conf +++ b/mkspecs/common/gcc-base-unix.conf @@ -16,6 +16,7 @@ QMAKE_LFLAGS_SONAME += -Wl,-soname, QMAKE_LFLAGS_THREAD += QMAKE_LFLAGS_RPATH = -Wl,-rpath, QMAKE_LFLAGS_RPATHLINK = -Wl,-rpath-link, +QMAKE_LFLAGS_NEW_DTAGS = -Wl,--enable-new-dtags QMAKE_LFLAGS_USE_GOLD = -fuse-ld=gold # -Bsymbolic-functions (ld) support diff --git a/mkspecs/common/gcc-base.conf b/mkspecs/common/gcc-base.conf index dc0aa4b4a9..27e812b3a1 100644 --- a/mkspecs/common/gcc-base.conf +++ b/mkspecs/common/gcc-base.conf @@ -43,7 +43,7 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g QMAKE_CFLAGS_DEBUG += -g QMAKE_CFLAGS_SHLIB += -fPIC QMAKE_CFLAGS_STATIC_LIB += -fPIC -QMAKE_CFLAGS_APP += -fPIE +QMAKE_CFLAGS_APP += -fPIC QMAKE_CFLAGS_ISYSTEM = -isystem QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden diff --git a/mkspecs/common/qcc-base.conf b/mkspecs/common/qcc-base.conf index 09fdabce43..4ef03d8587 100644 --- a/mkspecs/common/qcc-base.conf +++ b/mkspecs/common/qcc-base.conf @@ -23,7 +23,7 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g QMAKE_CFLAGS_DEBUG += -g QMAKE_CFLAGS_SHLIB += -fPIC -shared QMAKE_CFLAGS_STATIC_LIB += -fPIC -QMAKE_CFLAGS_APP += -fPIE +QMAKE_CFLAGS_APP += -fPIC QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden QMAKE_CFLAGS_SSE2 += -msse2 diff --git a/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in new file mode 100644 index 0000000000..c6419660c1 --- /dev/null +++ b/mkspecs/common/winrt_winphone/manifests/10.0/AppxManifest.xml.in @@ -0,0 +1,49 @@ + + + + + + + + + + $${WINRT_MANIFEST.name} + $${WINRT_MANIFEST.publisher} + $${WINRT_MANIFEST.logo_store} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mkspecs/common/winrt_winphone/qmake.conf b/mkspecs/common/winrt_winphone/qmake.conf index d71915408d..97ef661230 100644 --- a/mkspecs/common/winrt_winphone/qmake.conf +++ b/mkspecs/common/winrt_winphone/qmake.conf @@ -50,7 +50,7 @@ QMAKE_CXXFLAGS_STL_OFF = QMAKE_CXXFLAGS_RTTI_ON = -GR QMAKE_CXXFLAGS_RTTI_OFF = QMAKE_CXXFLAGS_EXCEPTIONS_ON = -EHsc -QMAKE_CXXFLAGS_EXCEPTIONS_OFF = +QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -D_HAS_EXCEPTIONS=0 QMAKE_INCDIR = diff --git a/mkspecs/devices/linux-beagleboard-g++/qmake.conf b/mkspecs/devices/linux-beagleboard-g++/qmake.conf index 3b9ca66306..1d32d374c6 100644 --- a/mkspecs/devices/linux-beagleboard-g++/qmake.conf +++ b/mkspecs/devices/linux-beagleboard-g++/qmake.conf @@ -36,8 +36,8 @@ QMAKE_CXXFLAGS_RELEASE += -O3 QMAKE_LIBS += -lrt -lpthread -ldl # Extra stuff (OpenGL, DirectFB, ...) -QMAKE_INCDIR_EGL = $$[QT_SYSROOT]/usr/include -QMAKE_LIBDIR_EGL = $$[QT_SYSROOT]/usr/lib +QMAKE_INCDIR_EGL = +QMAKE_LIBDIR_EGL = QMAKE_INCDIR_OPENGL_ES2 = $${QMAKE_INCDIR_EGL} QMAKE_LIBDIR_OPENGL_ES2 = $${QMAKE_LIBDIR_EGL} QMAKE_INCDIR_OPENVG = $${QMAKE_INCDIR_EGL} diff --git a/mkspecs/devices/linux-imx53qsb-g++/qmake.conf b/mkspecs/devices/linux-imx53qsb-g++/qmake.conf index 937bbf2416..39462d83d9 100644 --- a/mkspecs/devices/linux-imx53qsb-g++/qmake.conf +++ b/mkspecs/devices/linux-imx53qsb-g++/qmake.conf @@ -16,15 +16,10 @@ include(../common/linux_device_pre.conf) -QMAKE_INCDIR += $$[QT_SYSROOT]/usr/include -QMAKE_LIBDIR += $$[QT_SYSROOT]/usr/lib - QMAKE_LIBS_EGL += -lEGL QMAKE_LIBS_OPENGL_ES2 += -lGLESv2 -lEGL QMAKE_LIBS_OPENVG += -lOpenVG -lEGL -QMAKE_LFLAGS += -Wl,-rpath-link,$$[QT_SYSROOT]/usr/lib - IMX5_CFLAGS = -march=armv7-a -mfpu=neon -DLINUX=1 -DEGL_API_FB=1 -Wno-psabi QMAKE_CFLAGS += $$IMX5_CFLAGS QMAKE_CXXFLAGS += $$IMX5_CFLAGS diff --git a/mkspecs/devices/linux-imx6-g++/qmake.conf b/mkspecs/devices/linux-imx6-g++/qmake.conf index 1646c5fe77..71e37845c3 100644 --- a/mkspecs/devices/linux-imx6-g++/qmake.conf +++ b/mkspecs/devices/linux-imx6-g++/qmake.conf @@ -4,15 +4,10 @@ include(../common/linux_device_pre.conf) -QMAKE_INCDIR += $$[QT_SYSROOT]/usr/include -QMAKE_LIBDIR += $$[QT_SYSROOT]/usr/lib - QMAKE_LIBS_EGL += -lEGL QMAKE_LIBS_OPENGL_ES2 += -lGLESv2 -lEGL -lGAL QMAKE_LIBS_OPENVG += -lOpenVG -lEGL -lGAL -QMAKE_LFLAGS += -Wl,-rpath-link,$$[QT_SYSROOT]/usr/lib - IMX6_CFLAGS = -march=armv7-a -mfpu=neon -DLINUX=1 -DEGL_API_FB=1 QMAKE_CFLAGS += $$IMX6_CFLAGS QMAKE_CXXFLAGS += $$IMX6_CFLAGS diff --git a/mkspecs/features/default_post.prf b/mkspecs/features/default_post.prf index e967399258..8e68b95dd5 100644 --- a/mkspecs/features/default_post.prf +++ b/mkspecs/features/default_post.prf @@ -63,6 +63,7 @@ debug { } use_gold_linker: QMAKE_LFLAGS += $$QMAKE_LFLAGS_USE_GOLD +enable_new_dtags: QMAKE_LFLAGS += $$QMAKE_LFLAGS_NEW_DTAGS dll:win32: QMAKE_LFLAGS += $$QMAKE_LFLAGS_DLL static:mac: QMAKE_LFLAGS += $$QMAKE_LFLAGS_STATIC_LIB diff --git a/mkspecs/features/default_pre.prf b/mkspecs/features/default_pre.prf index b06b9d6cfc..eb3281ea1d 100644 --- a/mkspecs/features/default_pre.prf +++ b/mkspecs/features/default_pre.prf @@ -7,3 +7,18 @@ CONFIG = \ lex yacc debug exceptions depend_includepath \ testcase_targets import_plugins import_qpa_plugin \ $$CONFIG + +!build_pass:defined(QT_EDITION, var):!equals(QT_EDITION, "OpenSource"):!equals(QT_EDITION, "Preview") { + # + # call license checker (but cache result for one day) + # + today = $$section(_DATE_, " ", 0, 2) + !isEqual(QMAKE_LICHECK_TIMESTAMP, $$today) { + !system("$$system_quote($$system_path($$[QT_HOST_BINS/src]/$$QT_LICHECK)) check" \ + "$$QT_RELEASE_DATE $$[QMAKE_SPEC] $$[QMAKE_XSPEC]"): \ + error("License check failed! Giving up ...") + + cache(QMAKE_LICHECK_TIMESTAMP, set stash, today) + } + unset(today) +} diff --git a/mkspecs/features/qt_build_config.prf b/mkspecs/features/qt_build_config.prf index 42046c238a..7197f84c9a 100644 --- a/mkspecs/features/qt_build_config.prf +++ b/mkspecs/features/qt_build_config.prf @@ -52,12 +52,6 @@ QMAKE_DIR_REPLACE_SANE = PRECOMPILED_DIR OBJECTS_DIR MOC_DIR RCC_DIR UI_DIR unset(modpath) } -mac { - !isEmpty(QMAKE_RPATHDIR){ - CONFIG += absolute_library_soname - } -} - cross_compile: \ CONFIG += force_bootstrap diff --git a/mkspecs/features/qt_common.prf b/mkspecs/features/qt_common.prf index 6a66b76305..5861941848 100644 --- a/mkspecs/features/qt_common.prf +++ b/mkspecs/features/qt_common.prf @@ -79,6 +79,9 @@ warnings_are_errors:warning_clean { # Work-around for bug https://code.google.com/p/android/issues/detail?id=58135 android: QMAKE_CXXFLAGS_WARN_ON += -Wno-error=literal-suffix } + } else:msvc { + # enable for MSVC 2012, MSVC 2013 + equals(MSVC_VER, "11.0")|equals(MSVC_VER, "12.0"): QMAKE_CXXFLAGS_WARN_ON += -WX } unset(ver) } diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 78be2e8473..a1c499610b 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -185,7 +185,7 @@ defineTest(qtAddRpathLink) { # paths OTOH need to be put there. pubqt = $$replace(1, -private$, _private) pubdep = $$resolve_depends(pubqt, "QT.") - privdep = $$resolve_depends(pubqt, "QT.", ".depends" ".private_depends" ".run_depends") + privdep = $$resolve_depends(pubqt, "QT.", ".depends" ".run_depends") privdep -= $$pubdep rpaths = for(dep, privdep): \ @@ -259,7 +259,7 @@ defineTest(qtAddToolEnv) { # target variable, dependency var name, [non-empty: prepare for system(), not make] defineTest(qtAddTargetEnv) { deps = $$replace($$2, -private$, _private) - deps = $$resolve_depends(deps, "QT.", ".depends" ".private_depends" ".run_depends") + deps = $$resolve_depends(deps, "QT.", ".depends" ".run_depends") !isEmpty(deps) { ptypes = for(dep, deps) { diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 66a7598597..5412f3778a 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -60,7 +60,7 @@ MODULE_DEFINES = $$MODULE_DEFINE $$MODULE_DEFINES load(qt_build_paths) -qt_no_install_library { +header_module { TEMPLATE = aux CONFIG += force_qt # Needed for the headers_clean tests. } else { @@ -104,7 +104,7 @@ mac:CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework) { QMAKE_TARGET_BUNDLE_PREFIX = org.qt-project #QMAKE_FRAMEWORK_VERSION = 4.0 CONFIG += sliced_bundle qt_framework - qt_no_install_library { + header_module { CONFIG += bundle QMAKE_BUNDLE_EXTENSION = .framework QMAKE_INFO_PLIST = $$QMAKESPEC/Info.plist.lib @@ -132,6 +132,9 @@ mac { QMAKE_CFLAGS += -fconstant-cfstrings QMAKE_CXXFLAGS += -fconstant-cfstrings } + + contains(QT_CONFIG, rpath): \ + QMAKE_SONAME_PREFIX = @rpath } DEFINES += QT_BUILDING_QT diff --git a/mkspecs/features/qt_module_pris.prf b/mkspecs/features/qt_module_pris.prf index 4ce03f4327..1d727847e2 100644 --- a/mkspecs/features/qt_module_pris.prf +++ b/mkspecs/features/qt_module_pris.prf @@ -91,15 +91,22 @@ MODULE_FWD_PRI = $$mod_work_pfx/qt_lib_$${MODULE_ID}.pri MODULE_PRIVATE_INCLUDES = \$\$QT_MODULE_INCLUDE_BASE/$$MODULE_INCNAME/$$VERSION \ \$\$QT_MODULE_INCLUDE_BASE/$$MODULE_INCNAME/$$VERSION/$$MODULE_INCNAME } - split_incpath: \ + split_incpath { MODULE_SHADOW_INCLUDES = $$replace(MODULE_INCLUDES, ^\\\$\\\$QT_MODULE_INCLUDE_BASE, \ $$MODULE_BASE_OUTDIR/include) + generated_privates: \ + MODULE_SHADOW_PRIVATE_INCLUDES = $$replace(MODULE_PRIVATE_INCLUDES, ^\\\$\\\$QT_MODULE_INCLUDE_BASE, \ + $$MODULE_BASE_OUTDIR/include) + } MODULE_INCLUDES += $$MODULE_AUX_INCLUDES MODULE_PRIVATE_INCLUDES += $$MODULE_PRIVATE_AUX_INCLUDES internal_module: \ MODULE_INCLUDES += $$MODULE_PRIVATE_INCLUDES - split_incpath: \ + split_incpath { MODULE_FWD_PRI_CONT_SUFFIX += "QT.$${MODULE_ID}.includes += $$val_escape(MODULE_SHADOW_INCLUDES)" + generated_privates: \ + MODULE_FWD_PRI_CONT_SUFFIX += "QT.$${MODULE}_private.includes += $$val_escape(MODULE_SHADOW_PRIVATE_INCLUDES)" + } MODULE_PRI_CONT = \ "QT.$${MODULE_ID}.VERSION = $${VERSION}" \ "QT.$${MODULE_ID}.MAJOR_VERSION = $$section(VERSION, ., 0, 0)" \ diff --git a/mkspecs/features/spec_post.prf b/mkspecs/features/spec_post.prf index c9578773fe..4d398059b2 100644 --- a/mkspecs/features/spec_post.prf +++ b/mkspecs/features/spec_post.prf @@ -109,9 +109,8 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \ } QMAKE_INSTALL_DIR = $$QMAKE_COPY_DIR equals(QMAKE_HOST.os, Windows) { - # Ugly (and broken for relative paths) hack to support cross-building for Unix. - QMAKE_SYMBOLIC_LINK = $$QMAKE_COPY - QMAKE_LN_SHLIB = $$QMAKE_SYMBOLIC_LINK + QMAKE_SYMBOLIC_LINK = $(QMAKE) -install ln -f -s + QMAKE_LN_SHLIB = $(QMAKE) -install ln -s } else { QMAKE_SYMBOLIC_LINK = ln -f -s QMAKE_LN_SHLIB = ln -s diff --git a/mkspecs/features/testlib_defines.prf b/mkspecs/features/testlib_defines.prf index 9176beb9dd..901e03a91d 100644 --- a/mkspecs/features/testlib_defines.prf +++ b/mkspecs/features/testlib_defines.prf @@ -1 +1,2 @@ -DEFINES += QT_TESTCASE_BUILDDIR=$$shell_quote(\"$$OUT_PWD\") +contains(TEMPLATE, vc.*): DEFINES += QT_TESTCASE_BUILDDIR=\"$$OUT_PWD\" +else: DEFINES += QT_TESTCASE_BUILDDIR=$$shell_quote(\"$$OUT_PWD\") diff --git a/mkspecs/linux-icc/qmake.conf b/mkspecs/linux-icc/qmake.conf index 8119c8aa09..9190aa9f28 100644 --- a/mkspecs/linux-icc/qmake.conf +++ b/mkspecs/linux-icc/qmake.conf @@ -12,7 +12,7 @@ QMAKE_LEXFLAGS = QMAKE_YACC = yacc QMAKE_YACCFLAGS = -d QMAKE_CFLAGS = -QMAKE_CFLAGS_APP = -fPIE +QMAKE_CFLAGS_APP = -fPIC QMAKE_CFLAGS_DEPS = -M QMAKE_CFLAGS_WARN_ON = -w1 -Wall -Wcheck -wd1572,873,2259,2261 QMAKE_CFLAGS_WARN_OFF = -w diff --git a/mkspecs/winrt-arm-msvc2015/qmake.conf b/mkspecs/winrt-arm-msvc2015/qmake.conf new file mode 100644 index 0000000000..fcb6d99aa9 --- /dev/null +++ b/mkspecs/winrt-arm-msvc2015/qmake.conf @@ -0,0 +1,32 @@ +# +# qmake configuration for winrt-arm-msvc2015 +# +# Written for Microsoft Visual C++ 2015 +# + +include(../common/winrt_winphone/qmake.conf) +QMAKE_COMPILER_DEFINES += _MSC_VER=1900 +DEFINES += WINAPI_FAMILY=WINAPI_FAMILY_APP ARM __ARM__ __arm__ + +QMAKE_CFLAGS += -FS +QMAKE_CXXFLAGS += -FS +QMAKE_LFLAGS += /MACHINE:ARM /NODEFAULTLIB:kernel32.lib + +QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib + +# Note that the order is important, ucrt(d) has to be first +# Otherwise the linker might use malloc from a different library +# but free_dbg() from the runtime, causing assert when deleting +# items from different heaps +CONFIG(debug, debug|release) { + QMAKE_LIBS = ucrtd.lib $$QMAKE_LIBS +} else { + QMAKE_LIBS = ucrt.lib $$QMAKE_LIBS +} + +VCPROJ_ARCH = ARM +MSVC_VER = 14.0 +WINSDK_VER = 10.0 +WINTARGET_VER = winv10.0 +WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/10.0/AppxManifest.xml.in +WINRT_MANIFEST.architecture = arm diff --git a/tests/auto/tools/qmake/testdata/functions/one/2.cpp b/mkspecs/winrt-arm-msvc2015/qplatformdefs.h similarity index 93% rename from tests/auto/tools/qmake/testdata/functions/one/2.cpp rename to mkspecs/winrt-arm-msvc2015/qplatformdefs.h index 8bdc2e59e8..c8f88524d9 100644 --- a/tests/auto/tools/qmake/testdata/functions/one/2.cpp +++ b/mkspecs/winrt-arm-msvc2015/qplatformdefs.h @@ -3,7 +3,7 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the test suite of the Qt Toolkit. +** This file is part of the qmake spec of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage @@ -30,3 +30,5 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + +#include "../common/winrt_winphone/qplatformdefs.h" diff --git a/mkspecs/winrt-x64-msvc2015/qmake.conf b/mkspecs/winrt-x64-msvc2015/qmake.conf new file mode 100644 index 0000000000..e8062f5364 --- /dev/null +++ b/mkspecs/winrt-x64-msvc2015/qmake.conf @@ -0,0 +1,32 @@ +# +# qmake configuration for winrt-x64-msvc2015 +# +# Written for Microsoft Visual C++ 2015 +# + +include(../common/winrt_winphone/qmake.conf) +QMAKE_COMPILER_DEFINES += _MSC_VER=1900 _WIN32 +DEFINES += WINAPI_FAMILY=WINAPI_FAMILY_APP X64 __X64__ __x64__ + +QMAKE_CFLAGS += -FS +QMAKE_CXXFLAGS += -FS +QMAKE_LFLAGS += /MACHINE:X64 /NODEFAULTLIB:kernel32.lib + +QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib + +# Note that the order is important, ucrt(d) has to be first +# Otherwise the linker might use malloc from a different library +# but free_dbg() from the runtime, causing assert when deleting +# items from different heaps +CONFIG(debug, debug|release) { + QMAKE_LIBS = ucrtd.lib $$QMAKE_LIBS +} else { + QMAKE_LIBS = ucrt.lib $$QMAKE_LIBS +} + +VCPROJ_ARCH = x64 +MSVC_VER = 14.0 +WINSDK_VER = 10.0 +WINTARGET_VER = winv10.0 +WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/10.0/AppxManifest.xml.in +WINRT_MANIFEST.architecture = x64 diff --git a/tests/auto/tools/qmake/testdata/functions/1.cpp b/mkspecs/winrt-x64-msvc2015/qplatformdefs.h similarity index 93% rename from tests/auto/tools/qmake/testdata/functions/1.cpp rename to mkspecs/winrt-x64-msvc2015/qplatformdefs.h index 8bdc2e59e8..c8f88524d9 100644 --- a/tests/auto/tools/qmake/testdata/functions/1.cpp +++ b/mkspecs/winrt-x64-msvc2015/qplatformdefs.h @@ -3,7 +3,7 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the test suite of the Qt Toolkit. +** This file is part of the qmake spec of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage @@ -30,3 +30,5 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + +#include "../common/winrt_winphone/qplatformdefs.h" diff --git a/mkspecs/winrt-x86-msvc2015/qmake.conf b/mkspecs/winrt-x86-msvc2015/qmake.conf new file mode 100644 index 0000000000..5b44a97e8d --- /dev/null +++ b/mkspecs/winrt-x86-msvc2015/qmake.conf @@ -0,0 +1,32 @@ +# +# qmake configuration for winrt-x86-msvc2015 +# +# Written for Microsoft Visual C++ 2015 +# + +include(../common/winrt_winphone/qmake.conf) +QMAKE_COMPILER_DEFINES += _MSC_VER=1900 _WIN32 +DEFINES += WINAPI_FAMILY=WINAPI_FAMILY_APP X86 __X86__ __x86__ + +QMAKE_CFLAGS += -FS +QMAKE_CXXFLAGS += -FS +QMAKE_LFLAGS += /SAFESEH /MACHINE:X86 /NODEFAULTLIB:kernel32.lib + +QMAKE_LIBS += windowscodecs.lib WindowsApp.lib runtimeobject.lib + +# Note that the order is important, ucrt(d) has to be first +# Otherwise the linker might use malloc from a different library +# but free_dbg() from the runtime, causing assert when deleting +# items from different heaps +CONFIG(debug, debug|release) { + QMAKE_LIBS = ucrtd.lib $$QMAKE_LIBS +} else { + QMAKE_LIBS = ucrt.lib $$QMAKE_LIBS +} + +VCPROJ_ARCH = Win32 +MSVC_VER = 14.0 +WINSDK_VER = 10.0 +WINTARGET_VER = winv10.0 +WINRT_MANIFEST = $$PWD/../common/winrt_winphone/manifests/10.0/AppxManifest.xml.in +WINRT_MANIFEST.architecture = x86 diff --git a/tests/auto/tools/qmake/testdata/functions/2.cpp b/mkspecs/winrt-x86-msvc2015/qplatformdefs.h similarity index 93% rename from tests/auto/tools/qmake/testdata/functions/2.cpp rename to mkspecs/winrt-x86-msvc2015/qplatformdefs.h index 8bdc2e59e8..c8f88524d9 100644 --- a/tests/auto/tools/qmake/testdata/functions/2.cpp +++ b/mkspecs/winrt-x86-msvc2015/qplatformdefs.h @@ -3,7 +3,7 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the test suite of the Qt Toolkit. +** This file is part of the qmake spec of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage @@ -30,3 +30,5 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + +#include "../common/winrt_winphone/qplatformdefs.h" diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index fcd6bf8308..deacac2c83 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -810,7 +810,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES ProStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"), &frameworkdirs = project->values("QMAKE_FRAMEWORKPATH"); - static const char * const libs[] = { "QMAKE_LFLAGS", "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", 0 }; + static const char * const libs[] = { "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", 0 }; for (int i = 0; libs[i]; i++) { tmp = project->values(libs[i]); for(int x = 0; x < tmp.count();) { @@ -821,9 +821,6 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) QString r = opt.mid(2).toQString(); fixForOutput(r); libdirs.append(r); - } else if(opt == "-prebind") { - project->values("QMAKE_DO_PREBINDING").append("TRUE"); - remove = true; } else if(opt.startsWith("-l")) { name = opt.mid(2).toQString(); QString lib("lib" + name); @@ -921,7 +918,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) if(!path.isEmpty() && !libdirs.contains(path)) libdirs += path; } - library = fileFixify(library, FileFixifyFromOutdir); + library = fileFixify(library, FileFixifyFromOutdir | FileFixifyAbsolute); QString key = keyFor(library); if (!project->values("QMAKE_PBX_LIBRARIES").contains(key)) { bool is_frmwrk = (library.endsWith(".framework")); @@ -1812,11 +1809,14 @@ ProjectBuilderMakefileGenerator::openOutput(QFile &file, const QString &build) c } output += QString("project.pbxproj"); file.setFileName(output); + bool ret = UnixMakefileGenerator::openOutput(file, build); + ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1); + Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2); + return ret; } - bool ret = UnixMakefileGenerator::openOutput(file, build); - ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir.section(Option::dir_sep, 0, -1); - Option::output_dir = pbx_dir.section(Option::dir_sep, 0, -2); - return ret; + + ((ProjectBuilderMakefileGenerator*)this)->pbx_dir = Option::output_dir; + return UnixMakefileGenerator::openOutput(file, build); } /* This function is such a hack it is almost pointless, but it diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index f5e8248af5..4a03fafd77 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2019,7 +2019,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) for(int i = 0; i < pre_deps.size(); ++i) deps << replaceExtraCompilerVariables(pre_deps.at(i), inpf, out, NoShell); } - QString cmd = replaceExtraCompilerVariables(tmp_cmd, inpf, out, LocalShell); + QString cmd = replaceExtraCompilerVariables(tmp_cmd, inpf, out, TargetShell); // NOTE: The var -> QMAKE_COMP_var replace feature is unsupported, do not use! for (ProStringList::ConstIterator it3 = vars.constBegin(); it3 != vars.constEnd(); ++it3) cmd.replace("$(" + (*it3) + ")", "$(QMAKE_COMP_" + (*it3)+")"); @@ -2240,7 +2240,7 @@ QString MakefileGenerator::buildArgs() QString ret; foreach (const QString &arg, Option::globals->qmake_args) - ret += " " + escapeFilePath(arg); + ret += " " + shellQuote(arg); return ret; } diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index efea807209..c4750cb8a4 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -612,7 +612,7 @@ UnixMakefileGenerator::processPrlFiles() ProStringList &prl_libs = project->values("QMAKE_CURRENT_PRL_LIBS"); if(!prl_libs.isEmpty()) { for(int prl = 0; prl < prl_libs.size(); ++prl) - l.insert(lit+prl+1, prl_libs.at(prl).toQString()); + l.insert(++lit, prl_libs.at(prl)); prl_libs.clear(); } } @@ -699,6 +699,7 @@ UnixMakefileGenerator::defaultInstall(const QString &t) return QString(); enum { NoBundle, SolidBundle, SlicedBundle } bundle = NoBundle; + bool isAux = (project->first("TEMPLATE") == "aux"); const QString root = "$(INSTALL_ROOT)"; ProStringList &uninst = project->values(ProKey(t + ".uninstall")); QString ret, destdir = project->first("DESTDIR").toQString(); @@ -773,21 +774,21 @@ UnixMakefileGenerator::defaultInstall(const QString &t) } src_targ = escapeFilePath(src_targ); dst_targ = escapeFilePath(dst_targ); - if(!ret.isEmpty()) - ret += "\n\t"; - QString copy_cmd("-"); + QString copy_cmd; if (bundle == SolidBundle) { - copy_cmd += "$(INSTALL_DIR) " + src_targ + ' ' + plain_targ; + copy_cmd += "-$(INSTALL_DIR) " + src_targ + ' ' + plain_targ; } else if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib")) { - copy_cmd += "$(INSTALL_FILE) " + src_targ + ' ' + dst_targ; - } else { + copy_cmd += "-$(INSTALL_FILE) " + src_targ + ' ' + dst_targ; + } else if (!isAux) { if (bundle == SlicedBundle) ret += mkdir_p_asstring("\"`dirname " + dst_targ + "`\"", false) + "\n\t"; - copy_cmd += "$(INSTALL_PROGRAM) " + src_targ + ' ' + dst_targ; + copy_cmd += "-$(INSTALL_PROGRAM) " + src_targ + ' ' + dst_targ; } if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") && project->values(ProKey(t + ".CONFIG")).indexOf("fix_rpath") != -1) { + if (!ret.isEmpty()) + ret += "\n\t"; if(!project->isEmpty("QMAKE_FIX_RPATH")) { ret += copy_cmd; ret += "\n\t-" + var("QMAKE_FIX_RPATH") + ' ' + dst_targ + ' ' + dst_targ; @@ -797,11 +798,14 @@ UnixMakefileGenerator::defaultInstall(const QString &t) } else { ret += copy_cmd; } - } else { + } else if (!copy_cmd.isEmpty()) { + if (!ret.isEmpty()) + ret += "\n\t"; ret += copy_cmd; } - if(project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib")) { + if (isAux) { + } else if (project->first("TEMPLATE") == "lib" && project->isActiveConfig("staticlib")) { if(!project->isEmpty("QMAKE_RANLIB")) ret += QString("\n\t$(RANLIB) ") + dst_targ; } else if (!project->isActiveConfig("debug_info") && !project->isActiveConfig("nostrip") @@ -820,7 +824,7 @@ UnixMakefileGenerator::defaultInstall(const QString &t) uninst.append("\n\t"); if (bundle == SolidBundle) uninst.append("-$(DEL_FILE) -r " + plain_targ); - else + else if (!isAux) uninst.append("-$(DEL_FILE) " + dst_targ); if (bundle == SlicedBundle) { int dstlen = project->first("DESTDIR").length(); diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 7c5f4b13ea..5cde7c4ac2 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -922,17 +922,18 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) } } } - QString bundle_dir_f = escapeFilePath(bundle_dir); - QHash::ConstIterator symIt = symlinks.constBegin(), - symEnd = symlinks.constEnd(); - for (; symIt != symEnd; ++symIt) { - bundledFiles << symIt.key(); - alldeps << symIt.key(); - t << escapeDependencyPath(symIt.key()) << ":\n\t" - << mkdir_p_asstring(bundle_dir) << "\n\t" - << "@$(SYMLINK) " << escapeFilePath(symIt.value()) << ' ' << bundle_dir_f << endl; - } - if (!project->first("QMAKE_FRAMEWORK_VERSION").isEmpty()) { + if (!symlinks.isEmpty()) { + QString bundle_dir_f = escapeFilePath(bundle_dir); + QHash::ConstIterator symIt = symlinks.constBegin(), + symEnd = symlinks.constEnd(); + for (; symIt != symEnd; ++symIt) { + bundledFiles << symIt.key(); + alldeps << symIt.key(); + t << escapeDependencyPath(symIt.key()) << ":\n\t" + << mkdir_p_asstring(bundle_dir) << "\n\t" + << "@$(SYMLINK) " << escapeFilePath(symIt.value()) << ' ' << bundle_dir_f << endl; + } + QString currentLink = bundle_dir + "Versions/Current"; QString currentLink_f = escapeDependencyPath(currentLink); bundledFiles << currentLink; diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index 6c2d2c6206..cbf7cf26dc 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -608,10 +608,13 @@ void VCXProjectWriter::write(XmlOutput &xml, VCProject &tool) xml.setIndentString(" "); + const QString toolsVersion = (tool.SdkVersion == QStringLiteral("10.0")) ? QStringLiteral("14.0") + : QStringLiteral("4.0"); + xml << decl("1.0", "utf-8") << tag("Project") << attrTag("DefaultTargets","Build") - << attrTag("ToolsVersion", "4.0") + << attrTag("ToolsVersion", toolsVersion) << attrTag("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003") << tag("ItemGroup") << attrTag("Label", "ProjectConfigurations"); @@ -640,7 +643,7 @@ void VCXProjectWriter::write(XmlOutput &xml, VCProject &tool) << tagValue("DefaultLanguage", "en") << tagValue("AppContainerApplication", "true") << tagValue("ApplicationType", isWinPhone ? "Windows Phone" : "Windows Store") - << tagValue("ApplicationTypeRevision", tool.SdkVersion); + << tagValue("ApplicationTypeRevision", tool.SdkVersion == "10.0" ? "8.2" : tool.SdkVersion); } xml << closetag(); diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index eb8ae23384..dfa8f8837b 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -176,11 +176,34 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t) const QString vcInstallDir = "/fake/vc_install_dir"; const QString kitDir = "/fake/sdk_install_dir"; #endif // Q_OS_WIN - QStringList incDirs; QStringList libDirs; QStringList binDirs; - if (isPhone) { + if (msvcVer == QStringLiteral("14.0")) { + binDirs << vcInstallDir + QStringLiteral("bin/") + compiler; + binDirs << vcInstallDir + QStringLiteral("bin/"); // Maybe remove for x86 again? + binDirs << kitDir + QStringLiteral("bin/") + (arch == QStringLiteral("arm") ? QStringLiteral("x86") : arch); + binDirs << vcInstallDir + QStringLiteral("../Common7/Tools/bin"); + binDirs << vcInstallDir + QStringLiteral("../Common7/Tools"); + binDirs << vcInstallDir + QStringLiteral("../Common7/ide"); + binDirs << kitDir + QStringLiteral("Windows Performance Toolkit/"); + + incDirs << vcInstallDir + QStringLiteral("include"); + incDirs << vcInstallDir + QStringLiteral("atlmfc/include"); + // ### Investigate why VS uses 10056 first + incDirs << kitDir + QStringLiteral("Include/10.0.10056.0/ucrt"); + incDirs << kitDir + QStringLiteral("Include/10.0.10069.0/ucrt"); + incDirs << kitDir + QStringLiteral("Include/10.0.10069.0/um"); + incDirs << kitDir + QStringLiteral("Include/10.0.10069.0/shared"); + incDirs << kitDir + QStringLiteral("Include/10.0.10069.0/winrt"); + + libDirs << vcInstallDir + QStringLiteral("lib/store/") + compilerArch; + libDirs << vcInstallDir + QStringLiteral("atlmfc/lib") + compilerArch; + // ### Investigate why VS uses 10056 first + libDirs << kitDir + QStringLiteral("lib/10.0.10056.0/ucrt/") + arch; + libDirs << kitDir + QStringLiteral("lib/10.0.10069.0/ucrt/") + arch; + libDirs << kitDir + QStringLiteral("lib/10.0.10069.0/um/") + arch; + } else if (isPhone) { QString sdkDir = vcInstallDir; if (!QDir(sdkDir).exists()) { fprintf(stderr, "Failed to find the Windows Phone SDK in %s.\n" @@ -208,7 +231,6 @@ NmakeMakefileGenerator::writeMakefile(QTextStream &t) << kitDir + QStringLiteral("/include/shared") << kitDir + QStringLiteral("/include/winrt"); } - // Inherit PATH binDirs << QString::fromLocal8Bit(qgetenv("PATH")).split(QLatin1Char(';')); diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h index 59136b16c8..7092da3e59 100644 --- a/qmake/generators/win32/msvc_objectmodel.h +++ b/qmake/generators/win32/msvc_objectmodel.h @@ -56,7 +56,8 @@ enum DotNET { NET2008 = 0x90, NET2010 = 0xa0, NET2012 = 0xb0, - NET2013 = 0xc0 + NET2013 = 0xc0, + NET2015 = 0xd0 }; /* diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 20113e5746..b8f9c8135d 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -71,6 +71,7 @@ struct DotNetCombo { const char *regKey; } dotNetCombo[] = { #ifdef Q_OS_WIN64 + {NET2015, "MSVC.NET 2015 (14.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\14.0\\Setup\\VC\\ProductDir"}, {NET2013, "MSVC.NET 2013 (12.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\12.0\\Setup\\VC\\ProductDir"}, {NET2013, "MSVC.NET 2013 Express Edition (12.0)", "Software\\Wow6432Node\\Microsoft\\VCExpress\\12.0\\Setup\\VC\\ProductDir"}, {NET2012, "MSVC.NET 2012 (11.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\11.0\\Setup\\VC\\ProductDir"}, @@ -84,6 +85,7 @@ struct DotNetCombo { {NET2003, "MSVC.NET 2003 (7.1)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\7.1\\Setup\\VC\\ProductDir"}, {NET2002, "MSVC.NET 2002 (7.0)", "Software\\Wow6432Node\\Microsoft\\VisualStudio\\7.0\\Setup\\VC\\ProductDir"}, #else + {NET2015, "MSVC.NET 2015 (14.0)", "Software\\Microsoft\\VisualStudio\\14.0\\Setup\\VC\\ProductDir"}, {NET2013, "MSVC.NET 2013 (12.0)", "Software\\Microsoft\\VisualStudio\\12.0\\Setup\\VC\\ProductDir"}, {NET2013, "MSVC.NET 2013 Express Edition (12.0)", "Software\\Microsoft\\VCExpress\\12.0\\Setup\\VC\\ProductDir"}, {NET2012, "MSVC.NET 2012 (11.0)", "Software\\Microsoft\\VisualStudio\\11.0\\Setup\\VC\\ProductDir"}, @@ -175,6 +177,8 @@ const char _slnHeader110[] = "Microsoft Visual Studio Solution File, Format "\n# Visual Studio 2012"; const char _slnHeader120[] = "Microsoft Visual Studio Solution File, Format Version 12.00" "\n# Visual Studio 2013"; +const char _slnHeader140[] = "Microsoft Visual Studio Solution File, Format Version 12.00" + "\n# Visual Studio 2015"; // The following UUID _may_ change for later servicepacks... // If so we need to search through the registry at // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\Projects @@ -401,6 +405,8 @@ QString VcprojGenerator::retrievePlatformToolSet() const return QStringLiteral("v110") + suffix; case NET2013: return QStringLiteral("v120") + suffix; + case NET2015: + return QStringLiteral("v140") + suffix; default: return QString(); } @@ -647,6 +653,8 @@ void VcprojGenerator::writeSubDirs(QTextStream &t) } switch (which_dotnet_version(project->first("MSVC_VER").toLatin1())) { + case NET2015: + t << _slnHeader140; case NET2013: t << _slnHeader120; break; @@ -972,6 +980,9 @@ void VcprojGenerator::initProject() // Own elements ----------------------------- vcProject.Name = project->first("QMAKE_ORIG_TARGET").toQString(); switch (which_dotnet_version(project->first("MSVC_VER").toLatin1())) { + case NET2015: + vcProject.Version = "14.00"; + break; case NET2013: vcProject.Version = "12.00"; break; diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index ab4f48685b..0d761b08a2 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -100,10 +100,13 @@ ProString Win32MakefileGenerator::fixLibFlag(const ProString &lib) { if (lib.startsWith('/')) { if (lib.startsWith("/LIBPATH:")) - return QStringLiteral("/LIBPATH:") + escapeFilePath(lib.mid(9)); + return QLatin1String("/LIBPATH:") + + escapeFilePath(Option::fixPathToTargetOS(lib.mid(9).toQString(), false)); + // This appears to be a user-supplied flag. Assume sufficient quoting. return lib; } - return escapeFilePath(lib); + // This must be a fully resolved library path. + return escapeFilePath(Option::fixPathToTargetOS(lib.toQString(), false)); } bool @@ -231,7 +234,7 @@ Win32MakefileGenerator::processPrlFiles() } ProStringList &prl_libs = project->values("QMAKE_CURRENT_PRL_LIBS"); for (int prl = 0; prl < prl_libs.size(); ++prl) - l.insert(lit + prl + 1, prl_libs.at(prl)); + l.insert(++lit, prl_libs.at(prl)); prl_libs.clear(); } @@ -791,7 +794,7 @@ QString Win32MakefileGenerator::defaultInstall(const QString &t) { if((t != "target" && t != "dlltarget") || (t == "dlltarget" && (project->first("TEMPLATE") != "lib" || !project->isActiveConfig("shared"))) || - project->first("TEMPLATE") == "subdirs") + project->first("TEMPLATE") == "subdirs" || project->first("TEMPLATE") == "aux") return QString(); const QString root = "$(INSTALL_ROOT)"; diff --git a/qmake/library/proitems.cpp b/qmake/library/proitems.cpp index e780259417..a610da6b69 100644 --- a/qmake/library/proitems.cpp +++ b/qmake/library/proitems.cpp @@ -159,6 +159,18 @@ QString &ProString::toQString(QString &tmp) const return tmp.setRawData(m_string.constData() + m_offset, m_length); } +/*! + * \brief ProString::prepareExtend + * \param extraLen number of new characters to be added + * \param thisTarget offset to which current contents should be moved + * \param extraTarget offset at which new characters will be added + * \return pointer to storage location for new characters + * + * Prepares the string for adding new characters. + * If the string is detached and has enough space, it will be changed in place. + * Otherwise, it will be replaced with a new string object, thus detaching. + * In either case, the hash will be reset. + */ QChar *ProString::prepareExtend(int extraLen, int thisTarget, int extraTarget) { if (m_string.isDetached() && m_length + extraLen <= m_string.capacity()) { @@ -473,4 +485,23 @@ ProFile::~ProFile() { } +ProString ProFile::getStr(const ushort *&tPtr) +{ + uint len = *tPtr++; + ProString ret(items(), tPtr - tokPtr(), len); + ret.setSource(this); + tPtr += len; + return ret; +} + +ProKey ProFile::getHashStr(const ushort *&tPtr) +{ + uint hash = *tPtr++; + hash |= (uint)*tPtr++ << 16; + uint len = *tPtr++; + ProKey ret(items(), tPtr - tokPtr(), len, hash); + tPtr += len; + return ret; +} + QT_END_NAMESPACE diff --git a/qmake/library/proitems.h b/qmake/library/proitems.h index d31367361d..9430d28521 100644 --- a/qmake/library/proitems.h +++ b/qmake/library/proitems.h @@ -352,6 +352,9 @@ public: bool isHostBuild() const { return m_hostBuild; } void setHostBuild(bool host_build) { m_hostBuild = host_build; } + ProString getStr(const ushort *&tPtr); + ProKey getHashStr(const ushort *&tPtr); + private: ProItemRefCount m_refCount; QString m_proitems; diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index e384d26f4c..02d5d5dd31 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -214,7 +214,7 @@ static QString windowsErrorCode() NULL); QString ret = QString::fromWCharArray(string); LocalFree((HLOCAL)string); - return ret; + return ret.trimmed(); } #endif @@ -362,7 +362,7 @@ QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::Open { QString errStr; if (!m_vfs->writeFile(fn, mode, contents, &errStr)) { - evalError(fL1S("Cannot write %1file %2: %3.") + evalError(fL1S("Cannot write %1file %2: %3") .arg(ctx, QDir::toNativeSeparators(fn), errStr)); return ReturnFalse; } @@ -1121,7 +1121,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( switch (func_t) { case T_DEFINED: { if (args.count() < 1 || args.count() > 2) { - evalError(fL1S("defined(function, [\"test\"|\"replace\"])" + evalError(fL1S("defined(function, [\"test\"|\"replace\"|\"var\"])" " requires one or two arguments.")); return ReturnFalse; } @@ -1582,7 +1582,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (rHand == INVALID_HANDLE_VALUE) { - evalError(fL1S("Cannot open() reference file %1: %2.").arg(rfn, windowsErrorCode())); + evalError(fL1S("Cannot open reference file %1: %2").arg(rfn, windowsErrorCode())); return ReturnFalse; } FILETIME ft; @@ -1592,7 +1592,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (wHand == INVALID_HANDLE_VALUE) { - evalError(fL1S("Cannot open() %1: %2.").arg(tfn, windowsErrorCode())); + evalError(fL1S("Cannot open %1: %2").arg(tfn, windowsErrorCode())); return ReturnFalse; } SetFileTime(wHand, 0, 0, &ft); diff --git a/qmake/library/qmakeevaluator.cpp b/qmake/library/qmakeevaluator.cpp index 723d5c7271..8e247d9afa 100644 --- a/qmake/library/qmakeevaluator.cpp +++ b/qmake/library/qmakeevaluator.cpp @@ -259,24 +259,6 @@ uint QMakeEvaluator::getBlockLen(const ushort *&tokPtr) return len; } -ProString QMakeEvaluator::getStr(const ushort *&tokPtr) -{ - uint len = *tokPtr++; - ProString ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len); - ret.setSource(m_current.pro); - tokPtr += len; - return ret; -} - -ProKey QMakeEvaluator::getHashStr(const ushort *&tokPtr) -{ - uint hash = getBlockLen(tokPtr); - uint len = *tokPtr++; - ProKey ret(m_current.pro->items(), tokPtr - m_current.pro->tokPtr(), len, hash); - tokPtr += len; - return ret; -} - void QMakeEvaluator::skipStr(const ushort *&tokPtr) { uint len = *tokPtr++; @@ -315,7 +297,8 @@ ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFil switch (unicode) { case '"': case '\'': - quote = unicode; + if (!quote) + quote = unicode; hadWord = true; break; case ' ': @@ -430,6 +413,7 @@ void QMakeEvaluator::evaluateExpression( const ushort *&tokPtr, ProStringList *ret, bool joined) { debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression"); + ProFile *pro = m_current.pro; if (joined) *ret << ProString(); bool pending = false; @@ -445,35 +429,35 @@ void QMakeEvaluator::evaluateExpression( m_current.line = *tokPtr++; break; case TokLiteral: { - const ProString &val = getStr(tokPtr); + const ProString &val = pro->getStr(tokPtr); debugMsg(2, "literal %s", dbgStr(val)); addStr(val, ret, pending, joined); break; } case TokHashLiteral: { - const ProKey &val = getHashStr(tokPtr); + const ProKey &val = pro->getHashStr(tokPtr); debugMsg(2, "hashed literal %s", dbgStr(val.toString())); addStr(val, ret, pending, joined); break; } case TokVariable: { - const ProKey &var = getHashStr(tokPtr); + const ProKey &var = pro->getHashStr(tokPtr); const ProStringList &val = values(map(var)); debugMsg(2, "variable %s => %s", dbgKey(var), dbgStrList(val)); addStrList(val, tok, ret, pending, joined); break; } case TokProperty: { - const ProKey &var = getHashStr(tokPtr); + const ProKey &var = pro->getHashStr(tokPtr); const ProString &val = propertyValue(var); debugMsg(2, "property %s => %s", dbgKey(var), dbgStr(val)); addStr(val, ret, pending, joined); break; } case TokEnvVar: { - const ProString &var = getStr(tokPtr); + const ProString &var = pro->getStr(tokPtr); const ProString &val = ProString(m_option->getEnv(var.toQString(m_tmp1))); debugMsg(2, "env var %s => %s", dbgStr(var), dbgStr(val)); addStr(val, ret, pending, joined); break; } case TokFuncName: { - const ProKey &func = getHashStr(tokPtr); + const ProKey &func = pro->getHashStr(tokPtr); debugMsg(2, "function %s", dbgKey(func)); addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined); break; } @@ -538,6 +522,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( { traceMsg("entering block"); ProStringList curr; + ProFile *pro = m_current.pro; bool okey = true, or_op = false, invert = false; uint blockLen; while (ushort tok = *tokPtr++) { @@ -597,7 +582,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( blockLen = getBlockLen(tokPtr); ret = visitProBlock(tokPtr); } else if (okey != or_op) { - const ProKey &variable = getHashStr(tokPtr); + const ProKey &variable = pro->getHashStr(tokPtr); uint exprLen = getBlockLen(tokPtr); const ushort *exprPtr = tokPtr; tokPtr += exprLen; @@ -617,7 +602,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( case TokTestDef: case TokReplaceDef: if (m_cumulative || okey != or_op) { - const ProKey &name = getHashStr(tokPtr); + const ProKey &name = pro->getHashStr(tokPtr); blockLen = getBlockLen(tokPtr); visitProFunctionDef(tok, name, tokPtr); traceMsg("defined %s function %s", @@ -797,8 +782,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( forever { if (infinite) { if (!variable.isEmpty()) - m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index++))); - if (index > 1000) { + m_valuemapStack.top()[variable] = ProStringList(ProString(QString::number(index))); + if (++index > 1000) { evalError(fL1S("Ran into infinite loop (> 1000 iterations).")); break; } diff --git a/qmake/library/qmakeevaluator.h b/qmake/library/qmakeevaluator.h index 4f2acf25ee..a60adde84e 100644 --- a/qmake/library/qmakeevaluator.h +++ b/qmake/library/qmakeevaluator.h @@ -150,8 +150,6 @@ public: { return b ? ReturnTrue : ReturnFalse; } static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr); - ProString getStr(const ushort *&tokPtr); - ProKey getHashStr(const ushort *&tokPtr); void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined); static ALWAYS_INLINE void skipStr(const ushort *&tokPtr); static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr); diff --git a/qmake/library/qmakeglobals.h b/qmake/library/qmakeglobals.h index 7c77450523..de46ebbe74 100644 --- a/qmake/library/qmakeglobals.h +++ b/qmake/library/qmakeglobals.h @@ -135,6 +135,7 @@ public: bool initProperties(); # else void setProperties(const QHash &props); + void setProperties(const QHash &props) { properties = props; } # endif ProString propertyValue(const ProKey &name) const { return properties.value(name); } #endif diff --git a/qmake/main.cpp b/qmake/main.cpp index 27969932bc..bde537dcca 100644 --- a/qmake/main.cpp +++ b/qmake/main.cpp @@ -163,6 +163,75 @@ static int doSed(int argc, char **argv) return 0; } +static int doLink(int argc, char **argv) +{ + bool isSymlink = false; + bool force = false; + QList inFiles; + for (int i = 0; i < argc; i++) { + if (!strcmp(argv[i], "-s")) { + isSymlink = true; + } else if (!strcmp(argv[i], "-f")) { + force = true; + } else if (argv[i][0] == '-') { + fprintf(stderr, "Error: unrecognized ln option '%s'\n", argv[i]); + return 3; + } else { + inFiles << argv[i]; + } + } + if (inFiles.size() != 2) { + fprintf(stderr, "Error: this ln requires exactly two file arguments\n"); + return 3; + } + if (!isSymlink) { + fprintf(stderr, "Error: this ln supports faking symlinks only\n"); + return 3; + } + QString target = QString::fromLocal8Bit(inFiles[0]); + QString linkname = QString::fromLocal8Bit(inFiles[1]); + + QDir destdir; + QFileInfo tfi(target); + QFileInfo lfi(linkname); + if (lfi.isDir()) { + destdir.setPath(linkname); + lfi.setFile(destdir, tfi.fileName()); + } else { + destdir.setPath(lfi.path()); + } + if (!destdir.exists()) { + fprintf(stderr, "Error: destination directory %s does not exist\n", qPrintable(destdir.path())); + return 1; + } + tfi.setFile(destdir.absoluteFilePath(tfi.filePath())); + if (!tfi.exists()) { + fprintf(stderr, "Error: this ln does not support symlinking non-existing targets\n"); + return 3; + } + if (tfi.isDir()) { + fprintf(stderr, "Error: this ln does not support symlinking directories\n"); + return 3; + } + if (lfi.exists()) { + if (!force) { + fprintf(stderr, "Error: %s exists\n", qPrintable(lfi.filePath())); + return 1; + } + if (!QFile::remove(lfi.filePath())) { + fprintf(stderr, "Error: cannot overwrite %s\n", qPrintable(lfi.filePath())); + return 1; + } + } + if (!QFile::copy(tfi.filePath(), lfi.filePath())) { + fprintf(stderr, "Error: cannot copy %s to %s\n", + qPrintable(tfi.filePath()), qPrintable(lfi.filePath())); + return 1; + } + + return 0; +} + static int doInstall(int argc, char **argv) { if (!argc) { @@ -171,6 +240,8 @@ static int doInstall(int argc, char **argv) } if (!strcmp(argv[0], "sed")) return doSed(argc - 1, argv + 1); + if (!strcmp(argv[0], "ln")) + return doLink(argc - 1, argv + 1); fprintf(stderr, "Error: unrecognized -install subcommand '%s'\n", argv[0]); return 3; } diff --git a/qtbase.pro b/qtbase.pro index bae2641404..51e8fb8760 100644 --- a/qtbase.pro +++ b/qtbase.pro @@ -46,6 +46,11 @@ equals(QMAKE_HOST.os, Windows) { } INSTALLS += qmake +#licheck +licheck.path = $$[QT_HOST_BINS] +licheck.files = $$PWD/bin/$$QT_LICHECK +exists($$licheck.files): INSTALLS += licheck + #syncqt syncqt.path = $$[QT_HOST_BINS] syncqt.files = $$PWD/bin/syncqt.pl diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp index 4fde295443..4a87488014 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp @@ -189,6 +189,7 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) return egl::Error(EGL_SUCCESS); } +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (defined(ANGLE_ENABLE_WINDOWS_STORE) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // Qt WP: eglPostSubBufferNV comes here if (x + width > mWidth) { width = mWidth - x; @@ -198,6 +199,7 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) { height = mHeight - y; } +#endif if (width == 0 || height == 0) { diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h index 81b9ea748d..0f70fe4615 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h @@ -38,7 +38,7 @@ class InspectableNativeWindow; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; -#else +#elif defined(ANGLE_ENABLE_D3D11) typedef IDXGISwapChain DXGISwapChain; typedef IDXGIFactory DXGIFactory; #endif @@ -60,9 +60,11 @@ class NativeWindow #endif static bool isValidNativeWindow(EGLNativeWindowType window); +#if defined(ANGLE_ENABLE_D3D11) HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, DXGI_FORMAT format, UINT width, UINT height, DXGISwapChain** swapChain); +#endif inline EGLNativeWindowType getNativeWindow() const { return mWindow; } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp index 298f3ccbd2..dc539cf66e 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp @@ -552,18 +552,18 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); - // Create a quad in homogeneous coordinates - float x1 = (x / float(mWidth)) * 2.0f - 1.0f; - float y1 = (y / float(mHeight)) * 2.0f - 1.0f; - float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; - float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; - #if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + // Create a quad in homogeneous coordinates + float x1 = -1.0f; + float y1 = -1.0f; + float x2 = 1.0f; + float y2 = 1.0f; + const float dim = std::max(mWidth, mHeight); - float u1 = x / dim; - float v1 = y / dim; - float u2 = (x + width) / dim; - float v2 = (y + height) / dim; + float u1 = 0; + float v1 = 0; + float u2 = float(width) / dim; + float v2 = float(height) / dim; const NativeWindow::RotationFlags flags = mNativeWindow.rotationFlags(); const bool rotateL = flags == NativeWindow::RotateLeft; @@ -573,6 +573,12 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); #else + // Create a quad in homogeneous coordinates + float x1 = (x / float(mWidth)) * 2.0f - 1.0f; + float y1 = (y / float(mHeight)) * 2.0f - 1.0f; + float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; + float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; + float u1 = x / float(mWidth); float v1 = y / float(mHeight); float u2 = (x + width) / float(mWidth); @@ -613,8 +619,8 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) viewport.TopLeftX = 0; viewport.TopLeftY = 0; #if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) - viewport.Width = (rotateL || rotateR) ? mHeight : mWidth; - viewport.Height = (rotateL || rotateR) ? mWidth : mHeight; + viewport.Width = (rotateL || rotateR) ? height : width; + viewport.Height = (rotateL || rotateR) ? width : height; #else viewport.Width = mWidth; viewport.Height = mHeight; diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp index 9d8f0bb96c..0a4f45b5b7 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp @@ -37,6 +37,7 @@ bool NativeWindow::isValidNativeWindow(EGLNativeWindowType window) return IsWindow(window) == TRUE; } +#if defined(ANGLE_ENABLE_D3D11) HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain** swapChain) @@ -65,4 +66,5 @@ HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory return factory->CreateSwapChain(device, &swapChainDesc, swapChain); } +#endif } diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp index 350526c867..fa9a69c5a1 100644 --- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp @@ -100,6 +100,7 @@ bool CoreWindowNativeWindow::registerForSizeChangeEvents() if (SUCCEEDED(result)) { result = mDisplayInformation->add_OrientationChanged(orientationChangedHandler.Get(), &mOrientationChangedEventToken); + orientationChangedHandler->Invoke(mDisplayInformation.Get(), nullptr); } #endif @@ -135,8 +136,8 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor } DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; - swapChainDesc.Width = width; - swapChainDesc.Height = height; + swapChainDesc.Width = mRotationFlags ? height : width; + swapChainDesc.Height = mRotationFlags ? width : height; swapChainDesc.Format = format; swapChainDesc.Stereo = FALSE; swapChainDesc.SampleDesc.Count = 1; diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp index ded73dbb48..62f3ca1207 100644 --- a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp +++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp @@ -101,12 +101,14 @@ EGLBoolean EGLAPIENTRY PostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLin return EGL_FALSE; } +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (defined(ANGLE_ENABLE_WINDOWS_STORE) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // Qt WP: Allow this entry point as a workaround if (!display->getExtensions().postSubBuffer) { // Spec is not clear about how this should be handled. SetGlobalError(Error(EGL_SUCCESS)); return EGL_TRUE; } +#endif error = eglSurface->postSubBuffer(x, y, width, height); if (error.isError()) diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index 017ae0741e..8d08f403ec 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -63,7 +63,7 @@ # include # include # if MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 -# define HAVE_BROKEN_WAITID_ALL 1 +# define HAVE_BROKEN_WAITID 1 # endif #endif @@ -109,10 +109,10 @@ static struct sigaction old_sigaction; static pthread_once_t forkfd_initialization = PTHREAD_ONCE_INIT; static ffd_atomic_int forkfd_status = FFD_ATOMIC_INIT(0); -#ifdef HAVE_BROKEN_WAITID_ALL -static int waitid_p_all_works = 0; +#ifdef HAVE_BROKEN_WAITID +static int waitid_works = 0; #else -static const int waitid_p_all_works = 1; +static const int waitid_works = 1; #endif static ProcessInfo *tryAllocateInSection(Header *header, ProcessInfo entries[], int maxCount) @@ -183,10 +183,13 @@ static int tryReaping(pid_t pid, siginfo_t *info) { /* reap the child */ #ifdef HAVE_WAITID - // we have waitid(2), which fills in siginfo_t for us - info->si_pid = 0; - return waitid(P_PID, pid, info, WEXITED | WNOHANG) == 0 && info->si_pid == pid; -#else + if (waitid_works) { + // we have waitid(2), which fills in siginfo_t for us + info->si_pid = 0; + return waitid(P_PID, pid, info, WEXITED | WNOHANG) == 0 && info->si_pid == pid; + } +#endif + int status; if (waitpid(pid, &status, WNOHANG) <= 0) return 0; // child did not change state @@ -206,7 +209,6 @@ static int tryReaping(pid_t pid, siginfo_t *info) } return 1; -#endif } static void freeInfo(Header *header, ProcessInfo *entry) @@ -246,7 +248,7 @@ static void sigchld_handler(int signum) memset(&info, 0, sizeof info); #ifdef HAVE_WAITID - if (!waitid_p_all_works) + if (!waitid_works) goto search_arrays; /* be optimistic: try to see if we can get the child that exited */ @@ -310,12 +312,14 @@ search_arrays: if (pid <= 0) continue; #ifdef HAVE_WAITID - /* The child might have been reaped by the block above in another thread, - * so first check if it's ready and, if it is, lock it */ - if (!isChildReady(pid, &info) || - !ffd_atomic_compare_exchange(&children.entries[i].pid, &pid, -1, - FFD_ATOMIC_RELAXED, FFD_ATOMIC_RELAXED)) - continue; + if (waitid_works) { + /* The child might have been reaped by the block above in another thread, + * so first check if it's ready and, if it is, lock it */ + if (!isChildReady(pid, &info) || + !ffd_atomic_compare_exchange(&children.entries[i].pid, &pid, -1, + FFD_ATOMIC_RELAXED, FFD_ATOMIC_RELAXED)) + continue; + } #endif if (tryReaping(pid, &info)) { /* this is our child, send notification and free up this entry */ @@ -331,12 +335,14 @@ search_arrays: if (pid <= 0) continue; #ifdef HAVE_WAITID - /* The child might have been reaped by the block above in another thread, - * so first check if it's ready and, if it is, lock it */ - if (!isChildReady(pid, &info) || - !ffd_atomic_compare_exchange(&array->entries[i].pid, &pid, -1, - FFD_ATOMIC_RELAXED, FFD_ATOMIC_RELAXED)) - continue; + if (waitid_works) { + /* The child might have been reaped by the block above in another thread, + * so first check if it's ready and, if it is, lock it */ + if (!isChildReady(pid, &info) || + !ffd_atomic_compare_exchange(&array->entries[i].pid, &pid, -1, + FFD_ATOMIC_RELAXED, FFD_ATOMIC_RELAXED)) + continue; + } #endif if (tryReaping(pid, &info)) { /* this is our child, send notification and free up this entry */ @@ -357,17 +363,19 @@ chain_handler: static void forkfd_initialize() { -#if defined(HAVE_BROKEN_WAITID_ALL) +#if defined(HAVE_BROKEN_WAITID) pid_t pid = fork(); if (pid == 0) { _exit(0); } else if (pid > 0) { siginfo_t info; waitid(P_ALL, 0, &info, WNOWAIT | WEXITED); - waitid_p_all_works = (info.si_pid != 0); + waitid_works = (info.si_pid != 0); + info.si_pid = 0; // now really reap the child waitid(P_PID, pid, &info, WEXITED); + waitid_works = waitid_works && (info.si_pid != 0); } #endif diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-thai.c b/src/3rdparty/harfbuzz/src/harfbuzz-thai.c index 7438d5994c..2d4627e4f7 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-thai.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-thai.c @@ -241,7 +241,7 @@ static HB_Bool HB_ThaiConvertStringToGlyphIndices (HB_ShaperItem *item) int lgn = 0; HB_Bool haveSaraAm = false; - cell_length = th_next_cell ((const unsigned char *)cstr + i, len - i, &tis_cell, true); /* !item->fixedPitch); */ + cell_length = (int)(th_next_cell ((const unsigned char *)cstr + i, len - i, &tis_cell, true)); /* !item->fixedPitch); */ haveSaraAm = (cstr[i + cell_length - 1] == (char)0xd3); /* set shaper item's log_clusters */ @@ -432,7 +432,7 @@ static void HB_ThaiAssignAttributes(const HB_UChar16 *string, hb_uint32 len, HB_ /* manage grapheme boundaries */ i = 0; while (i < len) { - cell_length = th_next_cell((const unsigned char *)cstr + i, len - i, &tis_cell, true); + cell_length = (hb_uint32)(th_next_cell((const unsigned char *)cstr + i, len - i, &tis_cell, true)); attributes[i].graphemeBoundary = true; for (j = 1; j < cell_length; j++) diff --git a/src/3rdparty/md4/md4.cpp b/src/3rdparty/md4/md4.cpp index 94ac6adf58..ec74958d69 100644 --- a/src/3rdparty/md4/md4.cpp +++ b/src/3rdparty/md4/md4.cpp @@ -180,7 +180,7 @@ static void md4_update(struct md4_context *ctx, const unsigned char *data, size_ saved_lo = ctx->lo; if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) ctx->hi++; - ctx->hi += size >> 29; + ctx->hi += (quint32)(size >> 29); used = saved_lo & 0x3f; diff --git a/src/3rdparty/pcre/AUTHORS b/src/3rdparty/pcre/AUTHORS index 5eee1af4c6..d33723f198 100644 --- a/src/3rdparty/pcre/AUTHORS +++ b/src/3rdparty/pcre/AUTHORS @@ -8,7 +8,7 @@ Email domain: cam.ac.uk University of Cambridge Computing Service, Cambridge, England. -Copyright (c) 1997-2014 University of Cambridge +Copyright (c) 1997-2015 University of Cambridge All rights reserved @@ -19,7 +19,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Emain domain: freemail.hu -Copyright(c) 2010-2014 Zoltan Herczeg +Copyright(c) 2010-2015 Zoltan Herczeg All rights reserved. @@ -30,7 +30,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Emain domain: freemail.hu -Copyright(c) 2009-2014 Zoltan Herczeg +Copyright(c) 2009-2015 Zoltan Herczeg All rights reserved. diff --git a/src/3rdparty/pcre/LICENCE b/src/3rdparty/pcre/LICENCE index 602e4ae680..9f6f98e477 100644 --- a/src/3rdparty/pcre/LICENCE +++ b/src/3rdparty/pcre/LICENCE @@ -6,7 +6,8 @@ and semantics are as close as possible to those of the Perl 5 language. Release 8 of PCRE is distributed under the terms of the "BSD" licence, as specified below. The documentation for PCRE, supplied in the "doc" -directory, is distributed under the same terms as the software itself. +directory, is distributed under the same terms as the software itself. The data +in the testdata directory is not copyrighted and is in the public domain. The basic library functions are written in C and are freestanding. Also included in the distribution is a set of C++ wrapper functions, and a @@ -24,7 +25,7 @@ Email domain: cam.ac.uk University of Cambridge Computing Service, Cambridge, England. -Copyright (c) 1997-2014 University of Cambridge +Copyright (c) 1997-2015 University of Cambridge All rights reserved. @@ -35,7 +36,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Emain domain: freemail.hu -Copyright(c) 2010-2014 Zoltan Herczeg +Copyright(c) 2010-2015 Zoltan Herczeg All rights reserved. @@ -46,7 +47,7 @@ Written by: Zoltan Herczeg Email local part: hzmester Emain domain: freemail.hu -Copyright(c) 2009-2014 Zoltan Herczeg +Copyright(c) 2009-2015 Zoltan Herczeg All rights reserved. diff --git a/src/3rdparty/pcre/pcre.h b/src/3rdparty/pcre/pcre.h index 20f04ebed4..58ed46a2a3 100644 --- a/src/3rdparty/pcre/pcre.h +++ b/src/3rdparty/pcre/pcre.h @@ -43,8 +43,8 @@ POSSIBILITY OF SUCH DAMAGE. #define PCRE_MAJOR 8 #define PCRE_MINOR 37 -#define PCRE_PRERELEASE -RC1 -#define PCRE_DATE 2015-02-03 +#define PCRE_PRERELEASE +#define PCRE_DATE 2015-04-28 /* When an application links to a PCRE DLL in Windows, the symbols that are imported have to be identified as such. When building PCRE, the appropriate diff --git a/src/3rdparty/pcre/pcre_compile.c b/src/3rdparty/pcre/pcre_compile.c index 6510835c17..0efad2645d 100644 --- a/src/3rdparty/pcre/pcre_compile.c +++ b/src/3rdparty/pcre/pcre_compile.c @@ -866,14 +866,6 @@ static const pcre_uint8 opcode_possessify[] = { }; -/* Structure for mutual recursion detection. */ - -typedef struct recurse_check { - struct recurse_check *prev; - const pcre_uchar *group; -} recurse_check; - - /************************************************* * Find an error text * @@ -5532,13 +5524,13 @@ for (;; ptr++) PUT(previous, 1, (int)(code - previous)); break; /* End of class handling */ } -#endif /* Even though any XCLASS list is now discarded, we must allow for its memory. */ if (lengthptr != NULL) *lengthptr += (int)(class_uchardata - class_uchardata_base); +#endif /* If there are no characters > 255, or they are all to be included or excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the diff --git a/src/3rdparty/pcre/pcre_internal.h b/src/3rdparty/pcre/pcre_internal.h index 1c5f4cefd6..dd0ac7fc91 100644 --- a/src/3rdparty/pcre/pcre_internal.h +++ b/src/3rdparty/pcre/pcre_internal.h @@ -2446,7 +2446,7 @@ typedef struct compile_data { BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */ BOOL check_lookbehind; /* Lookbehinds need later checking */ BOOL dupnames; /* Duplicate names exist */ - BOOL iscondassert; /* Next assert is a condition */ + BOOL iscondassert; /* Next assert is a condition */ int nltype; /* Newline type */ int nllen; /* Newline string length */ pcre_uchar nl[4]; /* Newline string when fixed length */ @@ -2460,6 +2460,13 @@ typedef struct branch_chain { pcre_uchar *current_branch; } branch_chain; +/* Structure for mutual recursion detection. */ + +typedef struct recurse_check { + struct recurse_check *prev; + const pcre_uchar *group; +} recurse_check; + /* Structure for items in a linked list that represents an explicit recursive call within the pattern; used by pcre_exec(). */ diff --git a/src/3rdparty/pcre/pcre_jit_compile.c b/src/3rdparty/pcre/pcre_jit_compile.c index dd378e097b..debdf6ef45 100644 --- a/src/3rdparty/pcre/pcre_jit_compile.c +++ b/src/3rdparty/pcre/pcre_jit_compile.c @@ -1533,7 +1533,11 @@ while (cc < ccend) { case OP_KET: if (PRIVATE_DATA(cc) != 0) + { private_data_length++; + SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); + cc += PRIVATE_DATA(cc + 1); + } cc += 1 + LINK_SIZE; break; @@ -1548,6 +1552,7 @@ while (cc < ccend) case OP_SBRAPOS: case OP_SCOND: private_data_length++; + SLJIT_ASSERT(PRIVATE_DATA(cc) != 0); cc += 1 + LINK_SIZE; break; @@ -1710,6 +1715,8 @@ do { count = 1; srcw[0] = PRIVATE_DATA(cc); + SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0); + cc += PRIVATE_DATA(cc + 1); } cc += 1 + LINK_SIZE; break; diff --git a/src/3rdparty/pcre/pcre_study.c b/src/3rdparty/pcre/pcre_study.c index a2458c4c96..998fe2325e 100644 --- a/src/3rdparty/pcre/pcre_study.c +++ b/src/3rdparty/pcre/pcre_study.c @@ -70,7 +70,7 @@ Arguments: code pointer to start of group (the bracket) startcode pointer to start of the whole pattern's code options the compiling options - int RECURSE depth + recurses chain of recurse_check to catch mutual recursion Returns: the minimum length -1 if \C in UTF-8 mode or (*ACCEPT) was encountered @@ -80,12 +80,13 @@ Returns: the minimum length static int find_minlength(const REAL_PCRE *re, const pcre_uchar *code, - const pcre_uchar *startcode, int options, int recurse_depth) + const pcre_uchar *startcode, int options, recurse_check *recurses) { int length = -1; /* PCRE_UTF16 has the same value as PCRE_UTF8. */ BOOL utf = (options & PCRE_UTF8) != 0; BOOL had_recurse = FALSE; +recurse_check this_recurse; register int branchlength = 0; register pcre_uchar *cc = (pcre_uchar *)code + 1 + LINK_SIZE; @@ -130,7 +131,7 @@ for (;;) case OP_SBRAPOS: case OP_ONCE: case OP_ONCE_NC: - d = find_minlength(re, cc, startcode, options, recurse_depth); + d = find_minlength(re, cc, startcode, options, recurses); if (d < 0) return d; branchlength += d; do cc += GET(cc, 1); while (*cc == OP_ALT); @@ -393,7 +394,7 @@ for (;;) ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(slot, 0)); if (cs == NULL) return -2; do ce += GET(ce, 1); while (*ce == OP_ALT); - if ((cc > cs && cc < ce) || recurse_depth > 10) + if (cc > cs && cc < ce) /* Simple recursion */ { d = 0; had_recurse = TRUE; @@ -401,8 +402,22 @@ for (;;) } else { - int dd = find_minlength(re, cs, startcode, options, recurse_depth+1); - if (dd < d) d = dd; + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; + if (r != NULL) /* Mutual recursion */ + { + d = 0; + had_recurse = TRUE; + break; + } + else + { + int dd; + this_recurse.prev = recurses; + this_recurse.group = cs; + dd = find_minlength(re, cs, startcode, options, &this_recurse); + if (dd < d) d = dd; + } } slot += re->name_entry_size; } @@ -418,14 +433,26 @@ for (;;) ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(cc, 1)); if (cs == NULL) return -2; do ce += GET(ce, 1); while (*ce == OP_ALT); - if ((cc > cs && cc < ce) || recurse_depth > 10) + if (cc > cs && cc < ce) /* Simple recursion */ { d = 0; had_recurse = TRUE; } else { - d = find_minlength(re, cs, startcode, options, recurse_depth + 1); + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; + if (r != NULL) /* Mutual recursion */ + { + d = 0; + had_recurse = TRUE; + } + else + { + this_recurse.prev = recurses; + this_recurse.group = cs; + d = find_minlength(re, cs, startcode, options, &this_recurse); + } } } else d = 0; @@ -474,12 +501,21 @@ for (;;) case OP_RECURSE: cs = ce = (pcre_uchar *)startcode + GET(cc, 1); do ce += GET(ce, 1); while (*ce == OP_ALT); - if ((cc > cs && cc < ce) || recurse_depth > 10) + if (cc > cs && cc < ce) /* Simple recursion */ had_recurse = TRUE; else { - branchlength += find_minlength(re, cs, startcode, options, - recurse_depth + 1); + recurse_check *r = recurses; + for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break; + if (r != NULL) /* Mutual recursion */ + had_recurse = TRUE; + else + { + this_recurse.prev = recurses; + this_recurse.group = cs; + branchlength += find_minlength(re, cs, startcode, options, + &this_recurse); + } } cc += 1 + LINK_SIZE; break; @@ -1503,7 +1539,7 @@ if ((re->options & PCRE_ANCHORED) == 0 && /* Find the minimum length of subject string. */ -switch(min = find_minlength(re, code, code, re->options, 0)) +switch(min = find_minlength(re, code, code, re->options, NULL)) { case -2: *errorptr = "internal error: missing capturing bracket"; return NULL; case -3: *errorptr = "internal error: opcode not recognized"; return NULL; diff --git a/src/3rdparty/pcre/sljit/sljitNativeARM_64.c b/src/3rdparty/pcre/sljit/sljitNativeARM_64.c index c5251be53d..b66455f756 100644 --- a/src/3rdparty/pcre/sljit/sljitNativeARM_64.c +++ b/src/3rdparty/pcre/sljit/sljitNativeARM_64.c @@ -1081,12 +1081,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(TMP_SP) | (0 << 10))); offs = (local_size - saved_regs_size) << (15 - 3); } else { - compiler->local_size += 2 * sizeof(sljit_sw); - local_size -= saved_regs_size; - saved_regs_size += 2 * sizeof(sljit_sw); - FAIL_IF(push_inst(compiler, STP_PRE | 29 | RT2(TMP_LR) - | RN(TMP_SP) | ((-(saved_regs_size >> 3) & 0x7f) << 15))); - offs = 2 << 15; + offs = 0 << 15; + if (saved_regs_size & 0x8) { + offs = 1 << 15; + saved_regs_size += sizeof(sljit_sw); + } + local_size -= saved_regs_size + SLJIT_LOCALS_OFFSET; + FAIL_IF(push_inst(compiler, SUBI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10))); } tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG; @@ -1122,6 +1123,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compil } if (local_size) FAIL_IF(push_inst(compiler, SUBI | RD(TMP_SP) | RN(TMP_SP) | (local_size << 10))); + FAIL_IF(push_inst(compiler, STP_PRE | 29 | RT2(TMP_LR) + | RN(TMP_SP) | ((-(16 >> 3) & 0x7f) << 15))); FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(TMP_SP) | (0 << 10))); } @@ -1145,8 +1148,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compi local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 0) + SLJIT_LOCALS_OFFSET; local_size = (local_size + 15) & ~0xf; - if (local_size > (63 * sizeof(sljit_sw))) - local_size += 2 * sizeof(sljit_sw); compiler->local_size = local_size; return SLJIT_SUCCESS; } @@ -1167,16 +1168,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi if (local_size <= (63 * sizeof(sljit_sw))) offs = (local_size - saved_regs_size) << (15 - 3); else { - saved_regs_size += 2 * sizeof(sljit_sw); - local_size -= saved_regs_size; + FAIL_IF(push_inst(compiler, LDP_PST | 29 | RT2(TMP_LR) + | RN(TMP_SP) | (((16 >> 3) & 0x7f) << 15))); + offs = 0 << 15; + if (saved_regs_size & 0x8) { + offs = 1 << 15; + saved_regs_size += sizeof(sljit_sw); + } + local_size -= saved_regs_size + SLJIT_LOCALS_OFFSET; if (local_size > 0xfff) { FAIL_IF(push_inst(compiler, ADDI | RD(TMP_SP) | RN(TMP_SP) | ((local_size >> 12) << 10) | (1 << 22))); local_size &= 0xfff; } if (local_size) FAIL_IF(push_inst(compiler, ADDI | RD(TMP_SP) | RN(TMP_SP) | (local_size << 10))); - local_size = saved_regs_size; - offs = 2 << 15; } tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG; @@ -1204,8 +1209,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compi if (prev != -1) FAIL_IF(push_inst(compiler, LDRI | RT(prev) | RN(TMP_SP) | (offs >> 5))); - FAIL_IF(push_inst(compiler, LDP_PST | 29 | RT2(TMP_LR) - | RN(TMP_SP) | (((local_size >> 3) & 0x7f) << 15))); + if (compiler->local_size <= (63 * sizeof(sljit_sw))) { + FAIL_IF(push_inst(compiler, LDP_PST | 29 | RT2(TMP_LR) + | RN(TMP_SP) | (((local_size >> 3) & 0x7f) << 15))); + } else { + FAIL_IF(push_inst(compiler, ADDI | RD(TMP_SP) | RN(TMP_SP) | (saved_regs_size << 10))); + } FAIL_IF(push_inst(compiler, RET | RN(TMP_LR))); return SLJIT_SUCCESS; diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index 178de363d2..12ae8a65d8 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -1092,7 +1092,9 @@ public class ExtractStyle { { try { InsetDrawable d = (InsetDrawable)drawable; - Object mInsetStateObject = getAccessibleField(InsetDrawable.class, "mInsetState").get(d); + // mInsetState changed to mState in Android 5.1 (22) + Object mInsetStateObject = getAccessibleField(InsetDrawable.class, (Build.VERSION.SDK_INT > 21) ? "mState" + : "mInsetState").get(d); Rect _padding = new Rect(); boolean hasPadding = d.getPadding(_padding); return getDrawable(getAccessibleField(mInsetStateObject.getClass(), "mDrawable").get(mInsetStateObject), filename, hasPadding ? _padding : null); diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index 73140839cc..d6cd49f44c 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -65,7 +65,6 @@ import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; -import android.widget.LinearLayout; import java.io.BufferedReader; import java.io.DataOutputStream; @@ -789,29 +788,7 @@ public class QtActivityDelegate 0, 0, metrics.xdpi, metrics.ydpi, metrics.scaledDensity); } - - ViewGroup layout = null; m_layout = new QtLayout(m_activity); - if (Build.VERSION.SDK_INT >= 14) { - try { - ActivityInfo activityInfo = m_activity.getPackageManager().getActivityInfo(m_activity.getComponentName(), - PackageManager.GET_META_DATA); - if (activityInfo.metaData == null - || !activityInfo.metaData.containsKey("android.app.allow_overlapping_system_ui") - || !activityInfo.metaData.getBoolean("android.app.allow_overlapping_system_ui")) { - layout = new LinearLayout(m_activity); - layout.setFitsSystemWindows(true); - layout.addView(m_layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - if (layout == null) - layout = m_layout; - m_editText = new QtEditText(m_activity, this); m_imm = (InputMethodManager)m_activity.getSystemService(Context.INPUT_METHOD_SERVICE); m_surfaces = new HashMap(); @@ -834,7 +811,7 @@ public class QtActivityDelegate Log.w("Qt A11y", "Unknown exception: " + e.toString()); } - m_activity.setContentView(layout, + m_activity.setContentView(m_layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java index 95af3c87ad..23e08f537a 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java @@ -187,7 +187,7 @@ public class QtActivity extends Activity QT_ANDROID_THEMES = new String[] {"Theme_Light"}; QT_ANDROID_DEFAULT_THEME = "Theme_Light"; } - else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT == 21){ + else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT >= 21){ QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"}; QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light"; } else { diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml index 779612cdaf..60c612976f 100644 --- a/src/android/templates/AndroidManifest.xml +++ b/src/android/templates/AndroidManifest.xml @@ -44,10 +44,6 @@ signal is sent! --> - - - - diff --git a/src/angle/patches/0006-ANGLE-Allow-Windows-Phone-to-communicate-swap-region.patch b/src/angle/patches/0006-ANGLE-Allow-Windows-Phone-to-communicate-swap-region.patch new file mode 100644 index 0000000000..5c6ef7b036 --- /dev/null +++ b/src/angle/patches/0006-ANGLE-Allow-Windows-Phone-to-communicate-swap-region.patch @@ -0,0 +1,145 @@ +From f0fb8d75bd2c7a894df1cb7e7d3dcd1ad0fd88d0 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Sun, 3 May 2015 20:55:04 +0300 +Subject: [PATCH] ANGLE: Allow Windows Phone to communicate swap region + +eglPostSubBufferNV is used to communicate the size of the window, as +otherwise there is no way for the renderer to know if the last frame was +rendered in landscape or portrait, causing rendering glitches when the +orientation changes. The rotation flags are utilized in a few additional +places now to fix some corner cases where the rotation was not applied. + +This patch should be squashed into "ANGLE-Improve-Windows-Phone-Support" +during the next ANGLE rebase. + +Task-number: QTBUG-44333 +Task-number: QTBUG-43502 +Change-Id: Iec37f7531854184819c30c87eab82d96d56ff133 +--- + .../angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp | 2 ++ + .../libANGLE/renderer/d3d/d3d11/SwapChain11.cpp | 28 +++++++++++++--------- + .../d3d/d3d11/winrt/CoreWindowNativeWindow.cpp | 5 ++-- + .../angle/src/libGLESv2/entry_points_egl_ext.cpp | 2 ++ + 4 files changed, 24 insertions(+), 13 deletions(-) + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +index 4fde295..4a87488 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +@@ -189,6 +189,7 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + return egl::Error(EGL_SUCCESS); + } + ++#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (defined(ANGLE_ENABLE_WINDOWS_STORE) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // Qt WP: eglPostSubBufferNV comes here + if (x + width > mWidth) + { + width = mWidth - x; +@@ -198,6 +199,7 @@ egl::Error SurfaceD3D::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + { + height = mHeight - y; + } ++#endif + + if (width == 0 || height == 0) + { +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +index 298f3cc..dc539cf 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/SwapChain11.cpp +@@ -552,18 +552,18 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + + d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); + ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + // Create a quad in homogeneous coordinates +- float x1 = (x / float(mWidth)) * 2.0f - 1.0f; +- float y1 = (y / float(mHeight)) * 2.0f - 1.0f; +- float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; +- float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; ++ float x1 = -1.0f; ++ float y1 = -1.0f; ++ float x2 = 1.0f; ++ float y2 = 1.0f; + +-#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + const float dim = std::max(mWidth, mHeight); +- float u1 = x / dim; +- float v1 = y / dim; +- float u2 = (x + width) / dim; +- float v2 = (y + height) / dim; ++ float u1 = 0; ++ float v1 = 0; ++ float u2 = float(width) / dim; ++ float v2 = float(height) / dim; + + const NativeWindow::RotationFlags flags = mNativeWindow.rotationFlags(); + const bool rotateL = flags == NativeWindow::RotateLeft; +@@ -573,6 +573,12 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, rotateR ? u1 : u2, rotateL ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, rotateL ? u1 : u2, rotateR ? v1 : v2); + #else ++ // Create a quad in homogeneous coordinates ++ float x1 = (x / float(mWidth)) * 2.0f - 1.0f; ++ float y1 = (y / float(mHeight)) * 2.0f - 1.0f; ++ float x2 = ((x + width) / float(mWidth)) * 2.0f - 1.0f; ++ float y2 = ((y + height) / float(mHeight)) * 2.0f - 1.0f; ++ + float u1 = x / float(mWidth); + float v1 = y / float(mHeight); + float u2 = (x + width) / float(mWidth); +@@ -613,8 +619,8 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + #if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +- viewport.Width = (rotateL || rotateR) ? mHeight : mWidth; +- viewport.Height = (rotateL || rotateR) ? mWidth : mHeight; ++ viewport.Width = (rotateL || rotateR) ? height : width; ++ viewport.Height = (rotateL || rotateR) ? width : height; + #else + viewport.Width = mWidth; + viewport.Height = mHeight; +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +index 350526c..fa9a69c 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/winrt/CoreWindowNativeWindow.cpp +@@ -100,6 +100,7 @@ bool CoreWindowNativeWindow::registerForSizeChangeEvents() + if (SUCCEEDED(result)) + { + result = mDisplayInformation->add_OrientationChanged(orientationChangedHandler.Get(), &mOrientationChangedEventToken); ++ orientationChangedHandler->Invoke(mDisplayInformation.Get(), nullptr); + } + #endif + +@@ -135,8 +136,8 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; +- swapChainDesc.Width = width; +- swapChainDesc.Height = height; ++ swapChainDesc.Width = mRotationFlags ? height : width; ++ swapChainDesc.Height = mRotationFlags ? width : height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; +diff --git a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp +index ded73db..62f3ca1 100644 +--- a/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/entry_points_egl_ext.cpp +@@ -101,12 +101,14 @@ EGLBoolean EGLAPIENTRY PostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLin + return EGL_FALSE; + } + ++#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (defined(ANGLE_ENABLE_WINDOWS_STORE) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // Qt WP: Allow this entry point as a workaround + if (!display->getExtensions().postSubBuffer) + { + // Spec is not clear about how this should be handled. + SetGlobalError(Error(EGL_SUCCESS)); + return EGL_TRUE; + } ++#endif + + error = eglSurface->postSubBuffer(x, y, width, height); + if (error.isError()) +-- +1.9.5.msysgit.0 + diff --git a/src/angle/patches/0007-ANGLE-Fix-compilation-without-d3d11.patch b/src/angle/patches/0007-ANGLE-Fix-compilation-without-d3d11.patch new file mode 100644 index 0000000000..eca7d0e162 --- /dev/null +++ b/src/angle/patches/0007-ANGLE-Fix-compilation-without-d3d11.patch @@ -0,0 +1,57 @@ +From 1f993a2492a618becd4bf89ef0d6cb5d2c9aa67a Mon Sep 17 00:00:00 2001 +From: Kai Koehne +Date: Mon, 11 May 2015 15:17:12 +0200 +Subject: [PATCH] ANGLE: Fix compilation without d3d11 + +Change-Id: I0b772698cf521083e5ecf35a395af57100a50131 +--- + src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h | 4 +++- + .../angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp | 2 ++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h +index 81b9ea7..0f70fe4 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/NativeWindow.h +@@ -38,7 +38,7 @@ class InspectableNativeWindow; + using namespace Microsoft::WRL; + using namespace Microsoft::WRL::Wrappers; + +-#else ++#elif defined(ANGLE_ENABLE_D3D11) + typedef IDXGISwapChain DXGISwapChain; + typedef IDXGIFactory DXGIFactory; + #endif +@@ -60,9 +60,11 @@ class NativeWindow + #endif + static bool isValidNativeWindow(EGLNativeWindowType window); + ++#if defined(ANGLE_ENABLE_D3D11) + HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, + DXGI_FORMAT format, UINT width, UINT height, + DXGISwapChain** swapChain); ++#endif + + inline EGLNativeWindowType getNativeWindow() const { return mWindow; } + +diff --git a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp +index 9d8f0bb..0a4f45b 100644 +--- a/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp ++++ b/src/3rdparty/angle/src/libANGLE/renderer/d3d/d3d11/win32/NativeWindow.cpp +@@ -37,6 +37,7 @@ bool NativeWindow::isValidNativeWindow(EGLNativeWindowType window) + return IsWindow(window) == TRUE; + } + ++#if defined(ANGLE_ENABLE_D3D11) + HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, + DXGI_FORMAT format, unsigned int width, unsigned int height, + DXGISwapChain** swapChain) +@@ -65,4 +66,5 @@ HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory + + return factory->CreateSwapChain(device, &swapChainDesc, swapChain); + } ++#endif + } +-- +1.9.5.msysgit.0 + diff --git a/src/angle/src/common/common.pri b/src/angle/src/common/common.pri index 63b80347d1..735c841ad8 100644 --- a/src/angle/src/common/common.pri +++ b/src/angle/src/common/common.pri @@ -13,7 +13,7 @@ lib_replace.CONFIG = path QMAKE_PRL_INSTALL_REPLACE += lib_replace # DirectX is included in the Windows 8 Kit, but everything else requires the DX SDK. -win32-msvc2012|win32-msvc2013|winrt { +winrt|if(msvc:!win32-msvc2005:!win32-msvc2008:!win32-msvc2010) { FXC = fxc.exe } else { DX_DIR = $$(DXSDK_DIR) diff --git a/src/angle/src/libGLESv2/libGLESv2.pro b/src/angle/src/libGLESv2/libGLESv2.pro index 1bf9af0436..5979b68098 100644 --- a/src/angle/src/libGLESv2/libGLESv2.pro +++ b/src/angle/src/libGLESv2/libGLESv2.pro @@ -329,6 +329,8 @@ angle_d3d11 { !static { DEF_FILE = $$ANGLE_DIR/src/libGLESv2/$${TARGET}.def mingw:equals(QT_ARCH, i386): DEF_FILE = $$ANGLE_DIR/src/libGLESv2/$${TARGET}_mingw32.def +} else { + DEFINES += DllMain=DllMain_ANGLE # prevent symbol from conflicting with the user's DllMain } float_converter.target = float_converter diff --git a/src/corelib/Qt5CoreConfigExtras.cmake.in b/src/corelib/Qt5CoreConfigExtras.cmake.in index 7213a844f5..65fd1f9383 100644 --- a/src/corelib/Qt5CoreConfigExtras.cmake.in +++ b/src/corelib/Qt5CoreConfigExtras.cmake.in @@ -70,8 +70,14 @@ set(_qt5_corelib_extra_includes) # Qt5_POSITION_INDEPENDENT_CODE variable is used in the # qt5_use_module # macro to add it. set(Qt5_POSITION_INDEPENDENT_CODE True) -set_property(TARGET Qt5::Core PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE \"ON\") -set(Qt5Core_EXECUTABLE_COMPILE_FLAGS \"-fPIE\") +set(Qt5Core_EXECUTABLE_COMPILE_FLAGS \"-fPIC\") +if (CMAKE_VERSION VERSION_LESS 2.8.12 + AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" + OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)) + set_property(TARGET Qt5::Core APPEND PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE \"ON\") +else() + set_property(TARGET Qt5::Core APPEND PROPERTY INTERFACE_COMPILE_OPTIONS $$QMAKE_CXXFLAGS_APP) +endif() !!IF !isEmpty(QT_NAMESPACE) list(APPEND Qt5Core_DEFINITIONS -DQT_NAMESPACE=$$QT_NAMESPACE) diff --git a/src/corelib/Qt5CoreMacros.cmake b/src/corelib/Qt5CoreMacros.cmake index a94caf0d25..18563764ad 100644 --- a/src/corelib/Qt5CoreMacros.cmake +++ b/src/corelib/Qt5CoreMacros.cmake @@ -333,8 +333,10 @@ if (NOT CMAKE_VERSION VERSION_LESS 2.8.9) set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG) set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO QT_NO_DEBUG) set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_MINSIZEREL QT_NO_DEBUG) - - if (Qt5_POSITION_INDEPENDENT_CODE) + if (Qt5_POSITION_INDEPENDENT_CODE + AND (CMAKE_VERSION VERSION_LESS 2.8.12 + AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" + OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0))) set_property(TARGET ${_target} PROPERTY POSITION_INDEPENDENT_CODE ${Qt5_POSITION_INDEPENDENT_CODE}) endif() endforeach() diff --git a/src/corelib/codecs/qicucodec.cpp b/src/corelib/codecs/qicucodec.cpp index 65cc337708..b375999aeb 100644 --- a/src/corelib/codecs/qicucodec.cpp +++ b/src/corelib/codecs/qicucodec.cpp @@ -121,7 +121,7 @@ struct MibToName { short index; }; -static MibToName mibToName[] = { +static const MibToName mibToName[] = { { 3, 0 }, { 4, 9 }, { 5, 20 }, diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 050f8f207f..8fef333a77 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -1147,13 +1147,30 @@ QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba) return codecForUtfText(ba, QTextCodec::codecForMib(/*Latin 1*/ 4)); } +/*! + \fn QTextCodec * QTextCodec::codecForTr () + \obsolete + + Returns the codec used by QObject::tr() on its argument. If this + function returns 0 (the default), tr() assumes Latin-1. + + \sa setCodecForTr() +*/ + +/*! + \fn QTextCodec::setCodecForTr ( QTextCodec * c ) + \obsolete + + Sets the codec used by QObject::tr() on its argument to c. If c + is 0 (the default), tr() assumes Latin-1. +*/ /*! \internal \since 4.3 - Determines whether the decoder encountered a failure while decoding the input. If - an error was encountered, the produced result is undefined, and gets converted as according - to the conversion flags. + Determines whether the decoder encountered a failure while decoding the + input. If an error was encountered, the produced result is undefined, and + gets converted as according to the conversion flags. */ bool QTextDecoder::hasFailure() const { diff --git a/src/corelib/codecs/qwindowscodec.cpp b/src/corelib/codecs/qwindowscodec.cpp index cf427c64b6..dded93ccb5 100644 --- a/src/corelib/codecs/qwindowscodec.cpp +++ b/src/corelib/codecs/qwindowscodec.cpp @@ -172,7 +172,7 @@ QString QWindowsLocalCodec::convertToUnicodeCharByChar(const char *chars, int le } #else QString s; - int size = mbstowcs(NULL, mb, length); + size_t size = mbstowcs(NULL, mb, length); if (size < 0) { Q_ASSERT("Error in CE TextCodec"); return QString(); @@ -181,7 +181,7 @@ QString QWindowsLocalCodec::convertToUnicodeCharByChar(const char *chars, int le ws[size +1] = 0; ws[size] = 0; size = mbstowcs(ws, mb, length); - for (int i=0; i< size; i++) + for (size_t i = 0; i < size; i++) s.append(QChar(ws[i])); delete [] ws; #endif diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf index df1ee4afea..502689e4c2 100644 --- a/src/corelib/doc/qtcore.qdocconf +++ b/src/corelib/doc/qtcore.qdocconf @@ -43,5 +43,8 @@ imagedirs += images excludedirs += snippets +excludefiles += ../../../examples/widgets/tools/customcompleter/doc/src/customcompleter.qdoc \ + ../../../examples/widgets/tools/codecs/doc/src/codecs.qdoc + navigation.landingpage = "Qt Core" navigation.cppclassespage = "Qt Core C++ Classes" diff --git a/src/corelib/doc/snippets/code/doc_src_resources.cpp b/src/corelib/doc/snippets/code/doc_src_resources.cpp index 430c0c92c1..ab97f609ac 100644 --- a/src/corelib/doc/snippets/code/doc_src_resources.cpp +++ b/src/corelib/doc/snippets/code/doc_src_resources.cpp @@ -48,7 +48,7 @@ MyClass::MyClass() : BaseClass() { Q_INIT_RESOURCE(resources); - QFile file("qrc:/myfile.dat"); + QFile file(":/myfile.dat"); ... } //! [5] @@ -60,7 +60,7 @@ int main(int argc, char *argv[]) QApplication app(argc, argv); Q_INIT_RESOURCE(graphlib); - QFile file("qrc:/graph.png"); + QFile file(":/graph.png"); ... return app.exec(); } diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp index 77ec85cc36..e3d76453d0 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qsystemsemaphore.cpp @@ -51,8 +51,9 @@ sem.release(2); // resources available == 3 //! [1] QSystemSemaphore sem("market", 5, QSystemSemaphore::Create); -sem.acquire(5); // acquire all 5 resources -sem.release(5); // release the 5 resources +for (int i = 0; i < 5; ++i) // acquire all 5 resources + sem.acquire(); +sem.release(5); // release the 5 resources //! [1] diff --git a/src/corelib/doc/src/statemachine.qdoc b/src/corelib/doc/src/statemachine.qdoc index 037b09810f..e44a603959 100644 --- a/src/corelib/doc/src/statemachine.qdoc +++ b/src/corelib/doc/src/statemachine.qdoc @@ -63,7 +63,7 @@ used to effectively embed the elements and semantics of statecharts in Qt applications. The framework integrates tightly with Qt's meta-object system; for example, transitions between states can be triggered by signals, and - states can be configured to set properties and invoke methods on QObjects. + states can be configured to set properties and invoke methods on {QObject}s. Qt's event system is used to drive the state machines. The state graph in the State Machine framework is hierarchical. States can be nested inside of @@ -126,9 +126,9 @@ The QState::entered() signal is emitted when the state is entered, and the QState::exited() signal is emitted when the state is exited. In the - following snippet, the button's showMaximized() slot will be called when - state \c s3 is entered, and the button's showMinimized() slot will be called - when \c s3 is exited: + following snippet, the button's \l {QPushButton::}{showMaximized()} slot + will be called when state \c s3 is entered, and the button's \l {QPushButton::}{showMinimized()} + slot will be called when \c s3 is exited: \snippet statemachine/main.cpp 5 @@ -151,7 +151,7 @@ Assume we wanted the user to be able to quit the application at any time by clicking a Quit button. In order to achieve this, we need to create a final state and make it the target of a transition associated with the Quit - button's clicked() signal. We could add a transition from each of \c s1, \c + button's \l{QPushButton::}{clicked()} signal. We could add a transition from each of \c s1, \c s2 and \c s3; however, this seems redundant, and one would also have to remember to add such a transition from every new state that is added in the future. @@ -184,8 +184,8 @@ \snippet statemachine/main2.cpp 1 In this case we want the application to quit when the state machine is - finished, so the machine's finished() signal is connected to the - application's quit() slot. + finished, so the machine's \l {QStateMachine::}{finished()} signal is connected to the + application's \l {QCoreApplication::}{quit()} slot. A child state can override an inherited transition. For example, the following code adds a transition that effectively causes the Quit button to @@ -290,7 +290,7 @@ \endomit When \c s1 's final state is entered, \c s1 will automatically emit - finished(). We use a signal transition to cause this event to trigger a + \l {QState::}{finished()}. We use a signal transition to cause this event to trigger a state change: \snippet statemachine/main3.cpp 1 @@ -302,7 +302,7 @@ encapsulation mechanism when building complex (deeply nested) state machines. (In the above example, you could of course create a transition directly from \c s1 's \c done state rather than relying on \c s1 's - finished() signal, but with the consequence that implementation details of + \l {QState::}{finished()} signal, but with the consequence that implementation details of \c s1 are exposed and depended on). For parallel state groups, the QState::finished() signal is emitted when \e @@ -365,8 +365,8 @@ \snippet statemachine/main4.cpp 1 - In the eventTest() reimplementation, we first check if the event type is the - desired one; if so, we cast the event to a StringEvent and perform the + In the \l {QAbstractTransition::}{eventTest()} reimplementation, we first check if the event type is the + desired one; if so, we cast the event to a \c StringEvent and perform the string comparison. The following is a statechart that uses the custom event and transition: @@ -486,7 +486,7 @@ message box will pop up before the geometry of the button has actually been set. To ensure that the message box does not pop up until the geometry actually reaches its final - value, we can use the state's propertiesAssigned() signal. The propertiesAssigned() signal will be + value, we can use the state's \l {QState::}{propertiesAssigned()} signal. The \l {QState::}{propertiesAssigned()} signal will be emitted when the property is assigned its final value, whether this is done immediately or after the animation has finished playing. @@ -503,14 +503,14 @@ has been assigned the defined value. If the global restore policy is set to QStateMachine::RestoreProperties, the state will not emit - the propertiesAssigned() signal until these have been executed as well. + the \l {QState::}{propertiesAssigned()} signal until these have been executed as well. \section1 What Happens If A State Is Exited Before The Animation Has Finished If a state has property assignments, and the transition into the state has animations for the properties, the state can potentially be exited before the properties have been assigned to the values defines by the state. This is true in particular when there are transitions out from the - state that do not depend on the propertiesAssigned signal, as described in the previous section. + state that do not depend on the \l {QState::}{propertiesAssigned()} signal, as described in the previous section. The State Machine API guarantees that a property assigned by the state machine either: \list @@ -563,13 +563,13 @@ The parent state machine treats the child machine as an \e atomic state in the state machine algorithm. The child state machine is self-contained; it maintains its own event queue and - configuration. In particular, note that the \l{QStateMachine::configuration()}{configuration} + configuration. In particular, note that the \l{QStateMachine::}{configuration()} of the child machine is not part of the parent machine's configuration (only the child machine itself is). States of the child state machine cannot be specified as targets of transitions in the parent state machine; only the child state machine itself can. Conversely, states of the parent state machine cannot be specified as targets of transitions in the child state machine. The child - state machine's \l{QState::finished()}{finished}() signal can be used to trigger a transition + state machine's \l{QState::}{finished}() signal can be used to trigger a transition in the parent machine. */ diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 4f611bddbc..91e8699472 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -2124,9 +2124,9 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion() # define USE_ETC_OS_RELEASE struct QUnixOSVersion { - // from /etc/os-release older /etc/lsb-release - QString productType; // $ID $DISTRIB_ID - QString productVersion; // $VERSION_ID $DISTRIB_RELEASE + // from /etc/os-release older /etc/lsb-release // redhat /etc/redhat-release // debian /etc/debian_version + QString productType; // $ID $DISTRIB_ID // single line file containing: // Debian + QString productVersion; // $VERSION_ID $DISTRIB_RELEASE // // single line file QString prettyName; // $PRETTY_NAME $DISTRIB_DESCRIPTION }; @@ -2138,24 +2138,32 @@ static QString unquote(const char *begin, const char *end) } return QString::fromLatin1(begin, end - begin); } - -static bool readEtcFile(QUnixOSVersion &v, const char *filename, - const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey) +static QByteArray getEtcFileContent(const char *filename) { // we're avoiding QFile here int fd = qt_safe_open(filename, O_RDONLY); if (fd == -1) - return false; + return QByteArray(); QT_STATBUF sbuf; if (QT_FSTAT(fd, &sbuf) == -1) { qt_safe_close(fd); - return false; + return QByteArray(); } QByteArray buffer(sbuf.st_size, Qt::Uninitialized); buffer.resize(qt_safe_read(fd, buffer.data(), sbuf.st_size)); qt_safe_close(fd); + return buffer; +} + +static bool readEtcFile(QUnixOSVersion &v, const char *filename, + const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey) +{ + + QByteArray buffer = getEtcFileContent(filename); + if (buffer.isEmpty()) + return false; const char *ptr = buffer.constData(); const char *end = buffer.constEnd(); @@ -2219,14 +2227,72 @@ static bool readEtcLsbRelease(QUnixOSVersion &v) } } - return ok; + // some distributions have a /etc/lsb-release file that does not provide the values + // we are looking for, i.e. DISTRIB_ID, DISTRIB_RELEASE and DISTRIB_DESCRIPTION. + // Assuming that neither DISTRIB_ID nor DISTRIB_RELEASE were found, or contained valid values, + // returning false for readEtcLsbRelease will allow further /etc/-release parsing. + return ok && !(v.productType.isEmpty() && v.productVersion.isEmpty()); } +#if defined(Q_OS_LINUX) +static QByteArray getEtcFileFirstLine(const char *fileName) +{ + QByteArray buffer = getEtcFileContent(fileName); + if (buffer.isEmpty()) + return QByteArray(); + + const char *ptr = buffer.constData(); + int eol = buffer.indexOf("\n"); + return QByteArray(ptr, eol).trimmed(); +} + +static bool readEtcRedHatRelease(QUnixOSVersion &v) +{ + // /etc/redhat-release analysed should be a one line file + // the format of its content is + // i.e. "Red Hat Enterprise Linux Workstation release 6.5 (Santiago)" + QByteArray line = getEtcFileFirstLine("/etc/redhat-release"); + if (line.isEmpty()) + return false; + + v.prettyName = QString::fromLatin1(line); + + const char keyword[] = "release "; + int releaseIndex = line.indexOf(keyword); + v.productType = QString::fromLatin1(line.mid(0, releaseIndex)).remove(QLatin1Char(' ')); + int spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword)); + v.productVersion = QString::fromLatin1(line.mid(releaseIndex + strlen(keyword), spaceIndex > -1 ? spaceIndex - releaseIndex - strlen(keyword) : -1)); + return true; +} + +static bool readEtcDebianVersion(QUnixOSVersion &v) +{ + // /etc/debian_version analysed should be a one line file + // the format of its content is + // i.e. "jessie/sid" + QByteArray line = getEtcFileFirstLine("/etc/debian_version"); + if (line.isEmpty()) + return false; + + v.productType = QStringLiteral("Debian"); + v.productVersion = QString::fromLatin1(line); + return true; +} +#endif + static bool findUnixOsVersion(QUnixOSVersion &v) { if (readEtcOsRelease(v)) return true; - return readEtcLsbRelease(v); + if (readEtcLsbRelease(v)) + return true; +#if defined(Q_OS_LINUX) + if (readEtcRedHatRelease(v)) + return true; + if (readEtcDebianVersion(v)) + return true; +#endif + return false; } # endif // USE_ETC_OS_RELEASE #endif // Q_OS_UNIX diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 55aa34223e..4eeee0fef4 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1090,9 +1090,10 @@ Q_CORE_EXPORT int qrand(); #define QT_MODULE(x) -#if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && !defined(__PIC__) && !defined(__PIE__) +#if !defined(QT_BOOTSTRAPPED) && defined(QT_REDUCE_RELOCATIONS) && defined(__ELF__) && \ + (!defined(__PIC__) || (defined(__PIE__) && defined(Q_CC_GNU) && Q_CC_GNU >= 500)) # error "You must build your code with position independent code if Qt was built with -reduce-relocations. "\ - "Compile your code with -fPIC or -fPIE." + "Compile your code with -fPIC (-fPIE is not enough)." #endif namespace QtPrivate { diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index d9d21c535c..88882bbe8f 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -972,8 +972,8 @@ struct QMessagePattern { QElapsedTimer timer; #endif #ifdef QLOGGING_HAVE_BACKTRACE - int backtraceDepth; QString backtraceSeparator; + int backtraceDepth; #endif bool fromEnvironment; @@ -986,8 +986,8 @@ QMessagePattern::QMessagePattern() : literals(0) , tokens(0) #ifdef QLOGGING_HAVE_BACKTRACE - , backtraceDepth(5) , backtraceSeparator(QLatin1Char('|')) + , backtraceDepth(5) #endif , fromEnvironment(false) { @@ -1737,7 +1737,7 @@ void qErrnoWarning(int code, const char *msg, ...) Example: \code - QT_MESSAGE_PATTERN="[%{time yyyyMMdd h:mm:ss.zzz t} %{if-debug}D{%endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}" + QT_MESSAGE_PATTERN="[%{time yyyyMMdd h:mm:ss.zzz t} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}" \endcode The default \a pattern is "%{if-category}%{category}: %{endif}%{message}". diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 123e2edf0e..cd0fc4da91 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -294,10 +294,13 @@ public: WindowCloseButtonHint = 0x08000000, MacWindowToolBarButtonHint = 0x10000000, BypassGraphicsProxyWidget = 0x20000000, - WindowOkButtonHint = 0x00080000, - WindowCancelButtonHint = 0x00100000, NoDropShadowWindowHint = 0x40000000, - WindowFullscreenButtonHint = 0x80000000 + WindowFullscreenButtonHint = 0x80000000, + + // The following enums have overlapping values with other enums. + // This was not intentional, but it's too late to change now. + WindowOkButtonHint = 0x00080000, // WindowTransparentForInput + WindowCancelButtonHint = 0x00100000 // WindowOverridesSystemGestures }; Q_DECLARE_FLAGS(WindowFlags, WindowType) diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index d4d7b631ad..2af04ab8d9 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -2955,15 +2955,19 @@ \enum Qt::NativeGestureType \since 5.2 - \value BeginNativeGesture - \value EndNativeGesture - \value PanNativeGesture - \value ZoomNativeGesture - \value SmartZoomNativeGesture - \value RotateNativeGesture - \value SwipeNativeGesture + This enum returns the gesture type. + + \value BeginNativeGesture Sent before gesture event stream. + \value EndNativeGesture Sent after gesture event stream. + \value PanNativeGesture Sent after a panning gesture. + Similar to a click-and-drag mouse movement. + \value ZoomNativeGesture Specifies the magnification delta in percent. + \value SmartZoomNativeGesture Boolean magnification state. + \value RotateNativeGesture Rotation delta in degrees. + \value SwipeNativeGesture Sent after a swipe movements. */ + /*! \enum Qt::NavigationMode \since 4.6 diff --git a/src/corelib/global/qtypetraits.h b/src/corelib/global/qtypetraits.h index 3a305713e6..488e257e0f 100644 --- a/src/corelib/global/qtypetraits.h +++ b/src/corelib/global/qtypetraits.h @@ -506,6 +506,27 @@ Q_STATIC_ASSERT((!is_unsigned::value)); Q_STATIC_ASSERT((!is_signed::value)); Q_STATIC_ASSERT(( is_signed::value)); +template struct is_default_constructible; + +template<> struct is_default_constructible +{ +protected: + template struct test { typedef char type; }; +public: + static bool const value = false; +}; +template<> struct is_default_constructible<>::test { typedef double type; }; + +template struct is_default_constructible : is_default_constructible<> +{ +private: + template static typename test::type sfinae(U*); + template static char sfinae(...); +public: + static bool const value = sizeof(sfinae(0)) > 1; +}; + + } // namespace QtPrivate QT_END_NAMESPACE diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 4c189bfe57..207de2a85b 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -187,7 +187,7 @@ win32 { } !nacl { - freebsd-*|mac|darwin-*|openbsd-*:{ + freebsd-*|mac|darwin-*|openbsd-*|netbsd-*:{ SOURCES += io/qfilesystemwatcher_kqueue.cpp HEADERS += io/qfilesystemwatcher_kqueue_p.h } diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp index 4ca07ba41d..cddd70f908 100644 --- a/src/corelib/io/qfileselector.cpp +++ b/src/corelib/io/qfileselector.cpp @@ -225,9 +225,13 @@ QString QFileSelector::select(const QString &filePath) const return d->select(filePath); } -static QString qrcScheme() +static bool isLocalScheme(const QString &file) { - return QStringLiteral("qrc"); + bool local = file == QStringLiteral("qrc"); +#ifdef Q_OS_ANDROID + local |= file == QStringLiteral("assets"); +#endif + return local; } /*! @@ -240,10 +244,10 @@ static QString qrcScheme() QUrl QFileSelector::select(const QUrl &filePath) const { Q_D(const QFileSelector); - if (filePath.scheme() != qrcScheme() && !filePath.isLocalFile()) + if (!isLocalScheme(filePath.scheme()) && !filePath.isLocalFile()) return filePath; QUrl ret(filePath); - if (filePath.scheme() == qrcScheme()) { + if (isLocalScheme(filePath.scheme())) { QString equivalentPath = QLatin1Char(':') + filePath.path(); QString selectedPath = d->select(equivalentPath); ret.setPath(selectedPath.remove(0, 1)); diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp index faaf7a00af..79f16a0839 100644 --- a/src/corelib/io/qfilesystementry.cpp +++ b/src/corelib/io/qfilesystementry.cpp @@ -255,15 +255,15 @@ QString QFileSystemEntry::completeSuffix() const bool QFileSystemEntry::isRelative() const { resolveFilePath(); - return (m_filePath.isEmpty() || (!m_filePath.isEmpty() && (m_filePath[0].unicode() != '/') - && (!(m_filePath.length() >= 2 && m_filePath[1].unicode() == ':')))); + return (m_filePath.isEmpty() || (!m_filePath.isEmpty() && (m_filePath.at(0).unicode() != '/') + && (!(m_filePath.length() >= 2 && m_filePath.at(1).unicode() == ':')))); } bool QFileSystemEntry::isAbsolute() const { resolveFilePath(); return (!m_filePath.isEmpty() && ((m_filePath.length() >= 3 - && (m_filePath[0].isLetter() && m_filePath[1].unicode() == ':' && m_filePath[2].unicode() == '/')) + && (m_filePath.at(0).isLetter() && m_filePath.at(1).unicode() == ':' && m_filePath.at(2).unicode() == '/')) || (m_filePath.length() >= 2 && (m_filePath.at(0) == QLatin1Char('/') && m_filePath.at(1) == QLatin1Char('/'))) )); } @@ -276,7 +276,7 @@ bool QFileSystemEntry::isRelative() const bool QFileSystemEntry::isAbsolute() const { resolveFilePath(); - return (!m_filePath.isEmpty() && (m_filePath[0].unicode() == '/')); + return (!m_filePath.isEmpty() && (m_filePath.at(0).unicode() == '/')); } #endif @@ -337,10 +337,10 @@ void QFileSystemEntry::findFileNameSeparators() const int i = m_filePath.size() - 1; for (; i >= stop; --i) { - if (m_filePath[i].unicode() == '.') { + if (m_filePath.at(i).unicode() == '.') { firstDotInFileName = lastDotInFileName = i; break; - } else if (m_filePath[i].unicode() == '/') { + } else if (m_filePath.at(i).unicode() == '/') { lastSeparator = i; break; } @@ -348,9 +348,9 @@ void QFileSystemEntry::findFileNameSeparators() const if (lastSeparator != i) { for (--i; i >= stop; --i) { - if (m_filePath[i].unicode() == '.') + if (m_filePath.at(i).unicode() == '.') firstDotInFileName = i; - else if (m_filePath[i].unicode() == '/') { + else if (m_filePath.at(i).unicode() == '/') { lastSeparator = i; break; } diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index 0bd46400d3..3a8f7bd0a9 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -52,7 +52,7 @@ # include "qfilesystemwatcher_win_p.h" #elif defined(USE_INOTIFY) # include "qfilesystemwatcher_inotify_p.h" -#elif defined(Q_OS_FREEBSD) || defined(Q_OS_IOS) +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_IOS) # include "qfilesystemwatcher_kqueue_p.h" #elif defined(Q_OS_OSX) # include "qfilesystemwatcher_fsevents_p.h" @@ -68,7 +68,7 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject // there is a chance that inotify may fail on Linux pre-2.6.13 (August // 2005), so we can't just new inotify directly. return QInotifyFileSystemWatcherEngine::create(parent); -#elif defined(Q_OS_FREEBSD) || defined(Q_OS_IOS) +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_IOS) return QKqueueFileSystemWatcherEngine::create(parent); #elif defined(Q_OS_OSX) return QFseventsFileSystemWatcherEngine::create(parent); diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index d68f33287d..07a2ff8f6b 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -38,9 +38,9 @@ #include "qiodevice_p.h" #include "qfile.h" #include "qstringlist.h" +#include "qdir.h" #include -#include #ifdef QIODEVICE_DEBUG # include @@ -80,10 +80,29 @@ void debugBinaryString(const char *data, qint64 maxlen) #define Q_VOID +static void checkWarnMessage(const QIODevice *device, const char *function, const char *what) +{ + QDebug d = qWarning(); + d.noquote(); + d.nospace(); + d << "QIODevice::" << function; +#ifndef QT_NO_QOBJECT + d << " (" << device->metaObject()->className(); + if (!device->objectName().isEmpty()) + d << ", \"" << device->objectName() << '"'; + if (const QFile *f = qobject_cast(device)) + d << ", \"" << QDir::toNativeSeparators(f->fileName()) << '"'; + d << ')'; +#else + Q_UNUSED(device) +#endif // !QT_NO_QOBJECT + d << ": " << what; +} + #define CHECK_MAXLEN(function, returnType) \ do { \ if (maxSize < 0) { \ - qWarning("QIODevice::"#function": Called with maxSize < 0"); \ + checkWarnMessage(this, #function, "Called with maxSize < 0"); \ return returnType; \ } \ } while (0) @@ -92,10 +111,10 @@ void debugBinaryString(const char *data, qint64 maxlen) do { \ if ((d->openMode & WriteOnly) == 0) { \ if (d->openMode == NotOpen) { \ - qWarning("QIODevice::"#function": device not open"); \ + checkWarnMessage(this, #function, "device not open"); \ return returnType; \ } \ - qWarning("QIODevice::"#function": ReadOnly device"); \ + checkWarnMessage(this, #function, "ReadOnly device"); \ return returnType; \ } \ } while (0) @@ -104,10 +123,10 @@ void debugBinaryString(const char *data, qint64 maxlen) do { \ if ((d->openMode & ReadOnly) == 0) { \ if (d->openMode == NotOpen) { \ - qWarning("QIODevice::"#function": device not open"); \ + checkWarnMessage(this, #function, "device not open"); \ return returnType; \ } \ - qWarning("QIODevice::"#function": WriteOnly device"); \ + checkWarnMessage(this, #function, "WriteOnly device"); \ return returnType; \ } \ } while (0) @@ -462,7 +481,7 @@ void QIODevice::setTextModeEnabled(bool enabled) { Q_D(QIODevice); if (!isOpen()) { - qWarning("QIODevice::setTextModeEnabled: The device is not open"); + checkWarnMessage(this, "setTextModeEnabled", "The device is not open"); return; } if (enabled) @@ -621,11 +640,11 @@ bool QIODevice::seek(qint64 pos) { Q_D(QIODevice); if (d->isSequential()) { - qWarning("QIODevice::seek: Cannot call seek on a sequential device"); + checkWarnMessage(this, "seek", "Cannot call seek on a sequential device"); return false; } if (d->openMode == NotOpen) { - qWarning("QIODevice::seek: The device is not open"); + checkWarnMessage(this, "seek", "The device is not open"); return false; } if (pos < 0) { @@ -922,9 +941,9 @@ QByteArray QIODevice::read(qint64 maxSize) Q_UNUSED(d); #endif - if (maxSize != qint64(int(maxSize))) { - qWarning("QIODevice::read: maxSize argument exceeds QByteArray size limit"); - maxSize = INT_MAX; + if (quint64(maxSize) >= QByteArray::MaxSize) { + checkWarnMessage(this, "read", "maxSize argument exceeds QByteArray size limit"); + maxSize = QByteArray::MaxSize - 1; } qint64 readBytes = 0; @@ -976,7 +995,7 @@ QByteArray QIODevice::readAll() // flush internal read buffer if (!(d->openMode & Text) && !d->buffer.isEmpty()) { - if (d->buffer.size() >= INT_MAX) + if (quint64(d->buffer.size()) >= QByteArray::MaxSize) return QByteArray(); result = d->buffer.readAll(); readBytes = result.size(); @@ -1055,7 +1074,7 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize) { Q_D(QIODevice); if (maxSize < 2) { - qWarning("QIODevice::readLine: Called with maxSize < 2"); + checkWarnMessage(this, "readLine", "Called with maxSize < 2"); return qint64(-1); } @@ -1159,9 +1178,9 @@ QByteArray QIODevice::readLine(qint64 maxSize) Q_UNUSED(d); #endif - if (maxSize > INT_MAX) { + if (quint64(maxSize) >= QByteArray::MaxSize) { qWarning("QIODevice::read: maxSize argument exceeds QByteArray size limit"); - maxSize = INT_MAX; + maxSize = QByteArray::MaxSize - 1; } result.resize(int(maxSize)); @@ -1169,7 +1188,7 @@ QByteArray QIODevice::readLine(qint64 maxSize) if (!result.size()) { // If resize fails or maxSize == 0, read incrementally if (maxSize == 0) - maxSize = INT_MAX; + maxSize = QByteArray::MaxSize - 1; // The first iteration needs to leave an extra byte for the terminating null result.resize(1); diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp index 4f5aeff395..2bd996d213 100644 --- a/src/corelib/io/qlockfile.cpp +++ b/src/corelib/io/qlockfile.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 David Faure +** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -66,9 +67,12 @@ QT_BEGIN_NAMESPACE If the process holding the lock crashes, the lock file stays on disk and can prevent any other process from accessing the shared resource, ever. For this reason, QLockFile - tries to detect such a "stale" lock file, based on the process ID written into the file, - and (in case that process ID got reused meanwhile), on the last modification time of - the lock file (30s by default, for the use case of a short-lived operation). + tries to detect such a "stale" lock file, based on the process ID written into the file. + To cover the situation that the process ID got reused meanwhile, the current process name is + compared to the name of the process that corresponds to the process ID from the lock file. + If the process names differ, the lock file is considered stale. + Additionally, the last modification time of the lock file (30s by default, for the use case of a + short-lived operation) is taken into account. If the lock file is found to be stale, it will be deleted. For the use case of protecting a resource over a long time, you should therefore call @@ -122,7 +126,7 @@ QLockFile::~QLockFile() The value of \a staleLockTime is used by lock() and tryLock() in order to determine when an existing lock file is considered stale, i.e. left over by a crashed process. This is useful for the case where the PID got reused - meanwhile, so the only way to detect a stale lock file is by the fact that + meanwhile, so one way to detect a stale lock file is by the fact that it has been around for a long time. \sa staleLockTime() diff --git a/src/corelib/io/qlockfile_p.h b/src/corelib/io/qlockfile_p.h index 0cfaa42849..168062f467 100644 --- a/src/corelib/io/qlockfile_p.h +++ b/src/corelib/io/qlockfile_p.h @@ -75,6 +75,7 @@ public: // Returns \c true if the lock belongs to dead PID, or is old. // The attempt to delete it will tell us if it was really stale or not, though. bool isApparentlyStale() const; + static QString processNameByPid(qint64 pid); #ifdef Q_OS_UNIX static int checkFcntlWorksAfterFlock(); diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index b817a24c74..d6ea2f1f2d 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 David Faure +** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -48,6 +49,15 @@ #include // kill #include // gethostname +#if defined(Q_OS_OSX) +# include +#elif defined(Q_OS_LINUX) +# include +# include +#elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS) +# include +#endif + QT_BEGIN_NAMESPACE static QByteArray localHostName() // from QHostInfo::localHostName(), modified to return a QByteArray @@ -185,16 +195,54 @@ bool QLockFilePrivate::isApparentlyStale() const { qint64 pid; QString hostname, appname; - if (!getLockInfo(&pid, &hostname, &appname)) - return false; - if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { - if (::kill(pid, 0) == -1 && errno == ESRCH) - return true; // PID doesn't exist anymore + if (getLockInfo(&pid, &hostname, &appname)) { + if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { + if (::kill(pid, 0) == -1 && errno == ESRCH) + return true; // PID doesn't exist anymore + const QString processName = processNameByPid(pid); + if (!processName.isEmpty()) { + QFileInfo fi(appname); + if (fi.isSymLink()) + fi.setFile(fi.symLinkTarget()); + if (processName != fi.fileName()) + return true; // PID got reused by a different application. + } + } } const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); return staleLockTime > 0 && age > staleLockTime; } +QString QLockFilePrivate::processNameByPid(qint64 pid) +{ +#if defined(Q_OS_OSX) + char name[1024]; + proc_name(pid, name, sizeof(name) / sizeof(char)); + return QString::fromUtf8(name); +#elif defined(Q_OS_LINUX) + if (!QFile::exists(QStringLiteral("/proc/version"))) + return QString(); + char exePath[64]; + char buf[PATH_MAX]; + memset(buf, 0, sizeof(buf)); + sprintf(exePath, "/proc/%lld/exe", pid); + if (readlink(exePath, buf, sizeof(buf)) < 0) { + // The pid is gone. Return some invalid process name to fail the test. + return QStringLiteral("/ERROR/"); + } + return QFileInfo(QString::fromUtf8(buf)).fileName(); +#elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS) + kinfo_proc *proc = kinfo_getproc(pid); + if (!proc) + return QString(); + QString name = QString::fromUtf8(proc->ki_comm); + free(proc); + return name; +#else + return QString(); +#endif +} + void QLockFile::unlock() { Q_D(QLockFile); diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index 9fe86e1ad8..5bd1ba04c9 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 David Faure +** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -126,27 +127,75 @@ bool QLockFilePrivate::isApparentlyStale() const { qint64 pid; QString hostname, appname; - if (!getLockInfo(&pid, &hostname, &appname)) - return false; // On WinRT there seems to be no way of obtaining information about other // processes due to sandboxing #ifndef Q_OS_WINRT - if (hostname == QString::fromLocal8Bit(localHostName())) { - HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); - if (!procHandle) - return true; - // We got a handle but check if process is still alive - DWORD dwR = ::WaitForSingleObject(procHandle, 0); - ::CloseHandle(procHandle); - if (dwR == WAIT_TIMEOUT) - return true; + if (getLockInfo(&pid, &hostname, &appname)) { + if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { + HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + if (!procHandle) + return true; + // We got a handle but check if process is still alive + DWORD dwR = ::WaitForSingleObject(procHandle, 0); + ::CloseHandle(procHandle); + if (dwR == WAIT_TIMEOUT) + return true; + const QString processName = processNameByPid(pid); + if (!processName.isEmpty() && processName != appname) + return true; // PID got reused by a different application. + } } -#endif // !Q_OS_WINRT +#else // !Q_OS_WINRT + Q_UNUSED(pid); + Q_UNUSED(hostname); + Q_UNUSED(appname); +#endif // Q_OS_WINRT const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); return staleLockTime > 0 && age > staleLockTime; } +QString QLockFilePrivate::processNameByPid(qint64 pid) +{ +#if !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE) + typedef DWORD (WINAPI *GetModuleFileNameExFunc)(HANDLE, HMODULE, LPTSTR, DWORD); + + HMODULE hPsapi = LoadLibraryA("psapi"); + if (!hPsapi) + return QString(); + + GetModuleFileNameExFunc qGetModuleFileNameEx + = (GetModuleFileNameExFunc)GetProcAddress(hPsapi, "GetModuleFileNameExW"); + if (!qGetModuleFileNameEx) { + FreeLibrary(hPsapi); + return QString(); + } + + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, DWORD(pid)); + if (!hProcess) { + FreeLibrary(hPsapi); + return QString(); + } + wchar_t buf[MAX_PATH]; + const DWORD length = qGetModuleFileNameEx(hProcess, NULL, buf, sizeof(buf) / sizeof(wchar_t)); + CloseHandle(hProcess); + FreeLibrary(hPsapi); + if (!length) + return QString(); + QString name = QString::fromWCharArray(buf, length); + int i = name.lastIndexOf(QLatin1Char('\\')); + if (i >= 0) + name.remove(0, i + 1); + i = name.lastIndexOf(QLatin1Char('.')); + if (i >= 0) + name.truncate(i); + return name; +#else + Q_UNUSED(pid); + return QString(); +#endif +} + void QLockFile::unlock() { Q_D(QLockFile); diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp index c17b42ef81..af1bb56fe9 100644 --- a/src/corelib/io/qnoncontiguousbytedevice.cpp +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -216,6 +216,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size() return byteArray->size(); } +qint64 QNonContiguousByteDeviceByteArrayImpl::pos() +{ + return currentPosition; +} + QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer rb) : QNonContiguousByteDevice(), currentPosition(0) { @@ -253,6 +258,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd() return currentPosition >= size(); } +qint64 QNonContiguousByteDeviceRingBufferImpl::pos() +{ + return currentPosition; +} + bool QNonContiguousByteDeviceRingBufferImpl::reset() { currentPosition = 0; @@ -381,6 +391,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size() return device->size() - initialPosition; } +qint64 QNonContiguousByteDeviceIoDeviceImpl::pos() +{ + if (device->isSequential()) + return -1; + + return device->pos(); +} + QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) { byteDevice = bd; diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h index 8b5bf3080a..38089dedd7 100644 --- a/src/corelib/io/qnoncontiguousbytedevice_p.h +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -61,6 +61,7 @@ public: virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0; virtual bool advanceReadPointer(qint64 amount) = 0; virtual bool atEnd() = 0; + virtual qint64 pos() { return -1; } virtual bool reset() = 0; virtual qint64 size() = 0; @@ -103,6 +104,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QByteArray* byteArray; qint64 currentPosition; @@ -118,6 +120,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QSharedPointer ringBuffer; qint64 currentPosition; @@ -135,6 +138,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QIODevice* device; QByteArray* currentReadBuffer; diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index cb6de29532..251b10ea89 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -104,6 +104,10 @@ using namespace ABI::Windows::Storage; #define Q_XDG_PLATFORM #endif +#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(Q_OS_IOS)) +#define QSETTINGS_USE_QSTANDARDPATHS +#endif + // ************************************************************************ // QConfFile @@ -1044,7 +1048,7 @@ static void initDefaultPaths(QMutexLocker *locker) windowsConfigPath(CSIDL_COMMON_APPDATA) + QDir::separator()); #else -#if defined(QT_NO_STANDARDPATHS) || !defined(Q_XDG_PLATFORM) +#ifndef QSETTINGS_USE_QSTANDARDPATHS // Non XDG platforms (OS X, iOS, Blackberry, Android...) have used this code path erroneously // for some time now. Moving away from that would require migrating existing settings. QString userPath; diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index beb5d29d54..04848a38e5 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -274,45 +274,67 @@ QT_BEGIN_NAMESPACE \endtable \table - \header \li Path type \li Android + \header \li Path type \li Android \li iOS \row \li DesktopLocation \li "/files" + \li "/" (not writable) \row \li DocumentsLocation \li "/Documents", "//Documents" + \li "/Documents" \row \li FontsLocation \li "/system/fonts" (not writable) + \li "/Documents/.fonts" \row \li ApplicationsLocation \li not supported (directory not readable) + \li not supported \row \li MusicLocation \li "/Music", "//Music" + \li "/Documents/Music" \row \li MoviesLocation \li "/Movies", "//Movies" + \li "/Documents/Movies" \row \li PicturesLocation \li "/Pictures", "//Pictures" + \li "/Documents/Pictures", "assets-library://" \row \li TempLocation \li "/cache" + \li "/tmp" \row \li HomeLocation \li "/files" + \li "/" (not writable) \row \li DataLocation \li "/files", "//files" + \li "/Library/Application Support" \row \li CacheLocation \li "/cache", "//cache" + \li "/Library/Caches" \row \li GenericDataLocation \li "" + \li "/Documents" \row \li RuntimeLocation \li "/cache" + \li not supported \row \li ConfigLocation \li "/files/settings" + \li "/Documents" \row \li GenericConfigLocation \li "/files/settings" (there is no shared settings) + \li "/Documents" \row \li DownloadLocation \li "/Downloads", "//Downloads" + \li "/Documents/Download" \row \li GenericCacheLocation \li "/cache" (there is no shared cache) + \li "/Library/Caches" \row \li AppDataLocation \li "/files", "//files" + \li "/Library/Application Support" \row \li AppConfigLocation \li "/files/settings" + \li "/Documents" + \row \li AppLocalDataLocation + \li "/files", "//files" + \li "/Library/Application Support" \endtable In the table above, \c is usually the organization name, the @@ -327,6 +349,12 @@ QT_BEGIN_NAMESPACE \note On Android, applications with open files on the external storage ( locations), will be killed if the external storage is unmounted. + \note On iOS, if you do pass \c {QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()} + as argument to \l{QFileDialog::setDirectory()}, + a native image picker dialog will be used for accessing the user's photo album. + The filename returned can be loaded using QFile and related APIs. + This feature was added in Qt 5.5. + \sa writableLocation(), standardLocations(), displayName(), locate(), locateAll() */ diff --git a/src/corelib/io/qstandardpaths_ios.mm b/src/corelib/io/qstandardpaths_ios.mm index 27d28526c2..eb85e2fd23 100644 --- a/src/corelib/io/qstandardpaths_ios.mm +++ b/src/corelib/io/qstandardpaths_ios.mm @@ -55,30 +55,31 @@ QString QStandardPaths::writableLocation(StandardLocation type) QString location; switch (type) { - case DesktopLocation: - location = pathForDirectory(NSDesktopDirectory); - break; case DocumentsLocation: location = pathForDirectory(NSDocumentDirectory); break; case FontsLocation: - location = bundlePath() + QLatin1String("/.fonts"); + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/.fonts"); break; case ApplicationsLocation: - location = pathForDirectory(NSApplicationDirectory); + // NSApplicationDirectory points to a non-existing write-protected path. break; case MusicLocation: - location = pathForDirectory(NSMusicDirectory); + // NSMusicDirectory points to a non-existing write-protected path. Use sensible fallback. + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Music"); break; case MoviesLocation: - location = pathForDirectory(NSMoviesDirectory); + // NSMoviesDirectory points to a non-existing write-protected path. Use sensible fallback. + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Movies"); break; case PicturesLocation: - location = pathForDirectory(NSPicturesDirectory); + // NSPicturesDirectory points to a non-existing write-protected path. Use sensible fallback. + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Pictures"); break; case TempLocation: location = QString::fromNSString(NSTemporaryDirectory()); break; + case DesktopLocation: case HomeLocation: location = bundlePath(); break; @@ -99,20 +100,12 @@ QString QStandardPaths::writableLocation(StandardLocation type) location = pathForDirectory(NSDocumentDirectory); break; case DownloadLocation: - location = pathForDirectory(NSDownloadsDirectory); + // NSDownloadsDirectory points to a non-existing write-protected path. + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Download"); break; - default: - break; - } - - switch (type) { case RuntimeLocation: break; default: - // All other types must return something, so use the document directory - // as a reasonable fall-back (which will always exist). - if (location.isEmpty()) - location = pathForDirectory(NSDocumentDirectory); break; } diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 7823787711..f82d0ff0a1 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -67,8 +67,20 @@ #endif #if defined(Q_OS_BSD4) -# define QT_STATFSBUF struct statvfs -# define QT_STATFS ::statvfs +# if defined(Q_OS_NETBSD) + define QT_STATFSBUF struct statvfs + define QT_STATFS ::statvfs +# else +# define QT_STATFSBUF struct statfs +# define QT_STATFS ::statfs +# endif + +# if !defined(ST_RDONLY) +# define ST_RDONLY MNT_RDONLY +# endif +# if !defined(_STATFS_F_FLAGS) +# define _STATFS_F_FLAGS 1 +# endif #elif defined(Q_OS_ANDROID) # define QT_STATFS ::statfs # define QT_STATFSBUF struct statfs @@ -122,11 +134,7 @@ public: inline QByteArray device() const; private: #if defined(Q_OS_BSD4) -# if defined(Q_OS_NETBSD) - struct statvfs *stat_buf; -# else - struct statfs *stat_buf; -# endif + QT_STATFSBUF *stat_buf; int entryCount; int currentIndex; #elif defined(Q_OS_SOLARIS) @@ -502,7 +510,7 @@ void QStorageInfoPrivate::retrieveVolumeInfo() bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize; bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize; bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize; -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) || defined (Q_OS_BSD4) #if defined(_STATFS_F_FLAGS) readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0; #endif diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 5fe4cfef9d..47b96d708f 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -464,7 +464,7 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes) } #if defined (QTEXTSTREAM_DEBUG) qDebug("QTextStreamPrivate::fillReadBuffer(), using %s codec", - codec->name().constData()); + codec ? codec->name().constData() : "no"); #endif #endif @@ -476,9 +476,10 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes) int oldReadBufferSize = readBuffer.size(); #ifndef QT_NO_TEXTCODEC // convert to unicode - readBuffer += codec->toUnicode(buf, bytesRead, &readConverterState); + readBuffer += Q_LIKELY(codec) ? codec->toUnicode(buf, bytesRead, &readConverterState) + : QString::fromLatin1(buf, bytesRead); #else - readBuffer += QString::fromLatin1(QByteArray(buf, bytesRead).constData()); + readBuffer += QString::fromLatin1(buf, bytesRead); #endif // reset the Text flag. @@ -564,7 +565,8 @@ void QTextStreamPrivate::flushWriteBuffer() codec = QTextCodec::codecForLocale(); #if defined (QTEXTSTREAM_DEBUG) qDebug("QTextStreamPrivate::flushWriteBuffer(), using %s codec (%s generating BOM)", - codec->name().constData(), writeConverterState.flags & QTextCodec::IgnoreHeader ? "not" : ""); + codec ? codec->name().constData() : "no", + !codec || (writeConverterState.flags & QTextCodec::IgnoreHeader) ? "not" : ""); #endif // convert from unicode to raw data @@ -572,7 +574,7 @@ void QTextStreamPrivate::flushWriteBuffer() QByteArray data = Q_LIKELY(codec) ? codec->fromUnicode(writeBuffer.data(), writeBuffer.size(), &writeConverterState) : writeBuffer.toLatin1(); #else - QByteArray data = writeBuffer.toLocal8Bit(); + QByteArray data = writeBuffer.toLatin1(); #endif writeBuffer.clear(); diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index 945b7df930..e6c570d1db 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -186,7 +186,7 @@ public: QString url(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; QString toString(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; QString toDisplayString(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; - QUrl adjusted(FormattingOptions options) const; + QUrl adjusted(FormattingOptions options) const Q_REQUIRED_RESULT; QByteArray toEncoded(FormattingOptions options = FullyEncoded) const; static QUrl fromEncoded(const QByteArray &url, ParsingMode mode = TolerantMode); @@ -243,7 +243,7 @@ public: QString fragment(ComponentFormattingOptions options = PrettyDecoded) const; void setFragment(const QString &fragment, ParsingMode mode = TolerantMode); - QUrl resolved(const QUrl &relative) const; + QUrl resolved(const QUrl &relative) const Q_REQUIRED_RESULT; bool isRelative() const; bool isParentOf(const QUrl &url) const; diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 1502e5dada..2cc5741250 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -36,7 +36,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -45,13 +44,11 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent) handle(INVALID_HANDLE_VALUE), readBufferMaxSize(0), actualReadBufferSize(0), - emitReadyReadTimer(new QTimer(this)), + stopped(true), readSequenceStarted(false), pipeBroken(false), readyReadEmitted(false) { - emitReadyReadTimer->setSingleShot(true); - connect(emitReadyReadTimer, SIGNAL(timeout()), SIGNAL(readyRead())); dataReadNotifier = new QWinOverlappedIoNotifier(this); connect(dataReadNotifier, &QWinOverlappedIoNotifier::notified, this, &QWindowsPipeReader::notified); } @@ -73,12 +70,7 @@ static bool qt_cancelIo(HANDLE handle, OVERLAPPED *overlapped) QWindowsPipeReader::~QWindowsPipeReader() { - if (readSequenceStarted) { - if (qt_cancelIo(handle, &overlapped)) - dataReadNotifier->waitForNotified(-1, &overlapped); - else - qErrnoWarning("QWindowsPipeReader: qt_cancelIo on handle %x failed.", handle); - } + stop(); } /*! @@ -89,9 +81,9 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) readBuffer.clear(); actualReadBufferSize = 0; handle = hPipeReadEnd; - ZeroMemory(&overlapped, sizeof(overlapped)); pipeBroken = false; readyReadEmitted = false; + stopped = false; if (hPipeReadEnd != INVALID_HANDLE_VALUE) { dataReadNotifier->setHandle(hPipeReadEnd); dataReadNotifier->setEnabled(true); @@ -100,13 +92,24 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) /*! Stops the asynchronous read sequence. - This function assumes that the file already has been closed. - It does not cancel any I/O operation. + If the read sequence is running then the I/O operation is canceled. */ void QWindowsPipeReader::stop() { - dataReadNotifier->setEnabled(false); + stopped = true; + if (readSequenceStarted) { + if (qt_cancelIo(handle, &overlapped)) { + dataReadNotifier->waitForNotified(-1, &overlapped); + } else { + const DWORD dwError = GetLastError(); + if (dwError != ERROR_NOT_FOUND) { + qErrnoWarning(dwError, "QWindowsPipeReader: qt_cancelIo on handle %x failed.", + handle); + } + } + } readSequenceStarted = false; + dataReadNotifier->setEnabled(false); handle = INVALID_HANDLE_VALUE; } @@ -119,7 +122,7 @@ qint64 QWindowsPipeReader::bytesAvailable() const } /*! - Stops the asynchronous read sequence. + Copies at most \c{maxlen} bytes from the internal read buffer to \c{data}. */ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) { @@ -147,9 +150,7 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) } if (!pipeBroken) { - if (!actualReadBufferSize) - emitReadyReadTimer->stop(); - if (!readSequenceStarted) + if (!readSequenceStarted && !stopped) startAsyncRead(); if (readSoFar == 0) return -2; // signal EWOULDBLOCK @@ -172,13 +173,41 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode, { if (&overlapped != notifiedOverlapped) return; - if (!completeAsyncRead(numberOfBytesRead, errorCode)) { + + switch (errorCode) { + case ERROR_SUCCESS: + break; + case ERROR_MORE_DATA: + // This is not an error. We're connected to a message mode + // pipe and the message didn't fit into the pipe's system + // buffer. We will read the remaining data in the next call. + break; + case ERROR_BROKEN_PIPE: + case ERROR_PIPE_NOT_CONNECTED: pipeBroken = true; + break; + default: + emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); + pipeBroken = true; + break; + } + + readSequenceStarted = false; + + // After the reader was stopped, the only reason why this function can be called is the + // completion of a cancellation. No signals should be emitted, and no new read sequence should + // be started in this case. + if (stopped) + return; + + if (pipeBroken) { emit pipeClosed(); return; } + + actualReadBufferSize += numberOfBytesRead; + readBuffer.truncate(actualReadBufferSize); startAsyncRead(); - emitReadyReadTimer->stop(); readyReadEmitted = true; emit readyRead(); } @@ -206,6 +235,7 @@ void QWindowsPipeReader::startAsyncRead() char *ptr = readBuffer.reserve(bytesToRead); readSequenceStarted = true; + ZeroMemory(&overlapped, sizeof(overlapped)); if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) { // We get notified by the QWinOverlappedIoNotifier - even in the synchronous case. return; @@ -239,38 +269,6 @@ void QWindowsPipeReader::startAsyncRead() } } -/*! - \internal - Sets the correct size of the read buffer after a read operation. - Returns \c false, if an error occurred or the connection dropped. - */ -bool QWindowsPipeReader::completeAsyncRead(DWORD bytesRead, DWORD errorCode) -{ - readSequenceStarted = false; - - switch (errorCode) { - case ERROR_SUCCESS: - break; - case ERROR_MORE_DATA: - // This is not an error. We're connected to a message mode - // pipe and the message didn't fit into the pipe's system - // buffer. We will read the remaining data in the next call. - break; - case ERROR_BROKEN_PIPE: - case ERROR_PIPE_NOT_CONNECTED: - return false; - default: - emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); - return false; - } - - actualReadBufferSize += bytesRead; - readBuffer.truncate(actualReadBufferSize); - if (!emitReadyReadTimer->isActive()) - emitReadyReadTimer->start(); - return true; -} - /*! \internal Returns the number of available bytes in the pipe. diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index 53872e2552..c8a66d9511 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -47,7 +47,6 @@ #include #include -#include #include #include @@ -89,7 +88,6 @@ private Q_SLOTS: void notified(quint32 numberOfBytesRead, quint32 errorCode, OVERLAPPED *notifiedOverlapped); private: - bool completeAsyncRead(DWORD bytesRead, DWORD errorCode); DWORD checkPipeState(); private: @@ -99,7 +97,7 @@ private: qint64 readBufferMaxSize; QRingBuffer readBuffer; qint64 actualReadBufferSize; - QTimer *emitReadyReadTimer; + bool stopped; bool readSequenceStarted; bool pipeBroken; bool readyReadEmitted; diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 05d58ac028..524bfd26cc 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -325,6 +325,7 @@ struct QCoreApplicationData { #ifndef QT_NO_LIBRARY app_libpaths = 0; #endif + applicationNameSet = false; } ~QCoreApplicationData() { #ifndef QT_NO_LIBRARY @@ -369,8 +370,8 @@ struct QCoreApplicationData { QString orgName, orgDomain; QString application; // application name, initially from argv[0], can then be modified. - QString applicationNameCompat; // for QDesktopServices. Only set explicitly. QString applicationVersion; + bool applicationNameSet; // true if setApplicationName was called #ifndef QT_NO_LIBRARY QStringList *app_libpaths; @@ -752,7 +753,8 @@ void QCoreApplication::init() QCoreApplication::self = this; // Store app name (so it's still available after QCoreApplication is destroyed) - coreappdata()->application = d_func()->appName(); + if (!coreappdata()->applicationNameSet) + coreappdata()->application = d_func()->appName(); QLoggingRegistry::instance()->init(); @@ -2349,13 +2351,13 @@ QString QCoreApplication::organizationDomain() */ void QCoreApplication::setApplicationName(const QString &application) { + coreappdata()->applicationNameSet = !application.isEmpty(); QString newAppName = application; if (newAppName.isEmpty() && QCoreApplication::self) newAppName = QCoreApplication::self->d_func()->appName(); if (coreappdata()->application == newAppName) return; coreappdata()->application = newAppName; - coreappdata()->applicationNameCompat = newAppName; #ifndef QT_NO_QOBJECT if (QCoreApplication::self) emit QCoreApplication::self->applicationNameChanged(); @@ -2373,7 +2375,7 @@ QString QCoreApplication::applicationName() // Exported for QDesktopServices (Qt4 behavior compatibility) Q_CORE_EXPORT QString qt_applicationName_noFallback() { - return coreappdata()->applicationNameCompat; + return coreappdata()->applicationNameSet ? coreappdata()->application : QString(); } /*! diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index cc8e961be1..1509996199 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -203,9 +203,9 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) } } - // Dispatch accumulated user events - if (sendPostedEvents(flags)) - return true; + // Additional user events have to be handled before timer events, but the function may not + // return yet. + const bool userEventsSent = sendPostedEvents(flags); emit aboutToBlock(); const QVector timerHandles = d->timerIdToHandle.values().toVector(); @@ -228,6 +228,9 @@ bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) return true; } emit awake(); + + if (userEventsSent) + return true; } while (flags & QEventLoop::WaitForMoreEvents); return false; } @@ -484,7 +487,8 @@ bool QEventDispatcherWinRT::event(QEvent *e) QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate() { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory); + HRESULT hr; + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory); Q_ASSERT_SUCCEEDED(hr); HANDLE interruptHandle = CreateEventEx(NULL, NULL, NULL, SYNCHRONIZE|EVENT_MODIFY_STATE); timerIdToHandle.insert(INTERRUPT_HANDLE, interruptHandle); diff --git a/src/corelib/kernel/qfunctions_winrt.h b/src/corelib/kernel/qfunctions_winrt.h index 3fff52a22c..7efd042456 100644 --- a/src/corelib/kernel/qfunctions_winrt.h +++ b/src/corelib/kernel/qfunctions_winrt.h @@ -131,9 +131,13 @@ generate_inline_return_func2(_putenv_s, errno_t, const char *, const char *) generate_inline_return_func0(tzset, void) generate_inline_return_func0(_tzset, void) -QT_BEGIN_NAMESPACE +namespace Microsoft { + namespace WRL { + template class ComPtr; + } +} -namespace Microsoft { namespace WRL { template class ComPtr; } } +QT_BEGIN_NAMESPACE namespace QWinRTFunctions { diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp index 097f641d19..108a01aab7 100644 --- a/src/corelib/kernel/qjni.cpp +++ b/src/corelib/kernel/qjni.cpp @@ -43,7 +43,7 @@ QT_BEGIN_NAMESPACE static inline QString keyBase() { - return QStringLiteral("%1%2%3"); + return QStringLiteral("%1%2:%3"); } static QString qt_convertJString(jstring string) @@ -72,15 +72,15 @@ typedef QHash JClassHash; Q_GLOBAL_STATIC(JClassHash, cachedClasses) Q_GLOBAL_STATIC(QReadWriteLock, cachedClassesLock) -static QString toDotEncodedClassName(const char *className) +static QByteArray toBinaryEncClassName(const QByteArray &className) { - return QString::fromLatin1(className).replace(QLatin1Char('/'), QLatin1Char('.')); + return QByteArray(className).replace('/', '.'); } -static jclass getCachedClass(const QString &classDotEnc, bool *isCached = 0) +static jclass getCachedClass(const QByteArray &classBinEnc, bool *isCached = 0) { QReadLocker locker(cachedClassesLock); - const QHash::const_iterator &it = cachedClasses->constFind(classDotEnc); + const QHash::const_iterator &it = cachedClasses->constFind(QString::fromLatin1(classBinEnc)); const bool found = (it != cachedClasses->constEnd()); if (isCached != 0) @@ -89,10 +89,12 @@ static jclass getCachedClass(const QString &classDotEnc, bool *isCached = 0) return found ? it.value() : 0; } -static jclass loadClassDotEnc(const QString &classDotEnc, JNIEnv *env) +inline static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false) { + const QByteArray &binEncClassName = binEncoded ? className : toBinaryEncClassName(className); + bool isCached = false; - jclass clazz = getCachedClass(classDotEnc, &isCached); + jclass clazz = getCachedClass(binEncClassName, &isCached); if (clazz != 0 || isCached) return clazz; @@ -102,11 +104,12 @@ static jclass loadClassDotEnc(const QString &classDotEnc, JNIEnv *env) QWriteLocker locker(cachedClassesLock); // did we lose the race? - const QHash::const_iterator &it = cachedClasses->constFind(classDotEnc); + const QLatin1String key(binEncClassName); + const QHash::const_iterator &it = cachedClasses->constFind(key); if (it != cachedClasses->constEnd()) return it.value(); - QJNIObjectPrivate stringName = QJNIObjectPrivate::fromString(classDotEnc); + QJNIObjectPrivate stringName = QJNIObjectPrivate::fromString(key); QJNIObjectPrivate classObject = classLoader.callObjectMethod("loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", stringName.object()); @@ -114,27 +117,40 @@ static jclass loadClassDotEnc(const QString &classDotEnc, JNIEnv *env) if (!exceptionCheckAndClear(env) && classObject.isValid()) clazz = static_cast(env->NewGlobalRef(classObject.object())); - cachedClasses->insert(classDotEnc, clazz); + cachedClasses->insert(key, clazz); return clazz; } -inline static jclass loadClass(const char *className, JNIEnv *env) -{ - return loadClassDotEnc(toDotEncodedClassName(className), env); -} - typedef QHash JMethodIDHash; Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID) Q_GLOBAL_STATIC(QReadWriteLock, cachedMethodIDLock) +static inline jmethodID getMethodID(JNIEnv *env, + jclass clazz, + const char *name, + const char *sig, + bool isStatic = false) +{ + jmethodID id = isStatic ? env->GetStaticMethodID(clazz, name, sig) + : env->GetMethodID(clazz, name, sig); + + if (exceptionCheckAndClear(env)) + return 0; + + return id; +} + static jmethodID getCachedMethodID(JNIEnv *env, jclass clazz, + const QByteArray &className, const char *name, const char *sig, bool isStatic = false) { - // TODO: We need to use something else then the ref. from clazz to avoid collisions. - const QString key = keyBase().arg(size_t(clazz)).arg(QLatin1String(name)).arg(QLatin1String(sig)); + if (className.isEmpty()) + return getMethodID(env, clazz, name, sig, isStatic); + + const QString key = keyBase().arg(QLatin1String(className)).arg(QLatin1String(name)).arg(QLatin1String(sig)); QHash::const_iterator it; { @@ -150,14 +166,7 @@ static jmethodID getCachedMethodID(JNIEnv *env, if (it != cachedMethodID->constEnd()) return it.value(); - jmethodID id = 0; - if (isStatic) - id = env->GetStaticMethodID(clazz, name, sig); - else - id = env->GetMethodID(clazz, name, sig); - - if (exceptionCheckAndClear(env)) - id = 0; + jmethodID id = getMethodID(env, clazz, name, sig, isStatic); cachedMethodID->insert(key, id); return id; @@ -168,13 +177,32 @@ typedef QHash JFieldIDHash; Q_GLOBAL_STATIC(JFieldIDHash, cachedFieldID) Q_GLOBAL_STATIC(QReadWriteLock, cachedFieldIDLock) +static inline jfieldID getFieldID(JNIEnv *env, + jclass clazz, + const char *name, + const char *sig, + bool isStatic = false) +{ + jfieldID id = isStatic ? env->GetStaticFieldID(clazz, name, sig) + : env->GetFieldID(clazz, name, sig); + + if (exceptionCheckAndClear(env)) + return 0; + + return id; +} + static jfieldID getCachedFieldID(JNIEnv *env, jclass clazz, + const QByteArray &className, const char *name, const char *sig, bool isStatic = false) { - const QString key = keyBase().arg(size_t(clazz)).arg(QLatin1String(name)).arg(QLatin1String(sig)); + if (className.isNull()) + return getFieldID(env, clazz, name, sig, isStatic); + + const QString key = keyBase().arg(QLatin1String(className)).arg(QLatin1String(name)).arg(QLatin1String(sig)); QHash::const_iterator it; { @@ -190,14 +218,7 @@ static jfieldID getCachedFieldID(JNIEnv *env, if (it != cachedFieldID->constEnd()) return it.value(); - jfieldID id = 0; - if (isStatic) - id = env->GetStaticFieldID(clazz, name, sig); - else - id = env->GetFieldID(clazz, name, sig); - - if (exceptionCheckAndClear(env)) - id = 0; + jfieldID id = getFieldID(env, clazz, name, sig, isStatic); cachedFieldID->insert(key, id); return id; @@ -251,7 +272,7 @@ JNIEnv *QJNIEnvironmentPrivate::operator->() jclass QJNIEnvironmentPrivate::findClass(const char *className, JNIEnv *env) { - const QString &classDotEnc = toDotEncodedClassName(className); + const QByteArray &classDotEnc = toBinaryEncClassName(className); bool isCached = false; jclass clazz = getCachedClass(classDotEnc, &isCached); @@ -260,9 +281,10 @@ jclass QJNIEnvironmentPrivate::findClass(const char *className, JNIEnv *env) if (found) return clazz; + const QLatin1String key(classDotEnc); if (env != 0) { // We got an env. pointer (We expect this to be the right env. and call FindClass()) QWriteLocker locker(cachedClassesLock); - const QHash::const_iterator &it = cachedClasses->constFind(classDotEnc); + const QHash::const_iterator &it = cachedClasses->constFind(key); // Did we lose the race? if (it != cachedClasses->constEnd()) return it.value(); @@ -274,11 +296,11 @@ jclass QJNIEnvironmentPrivate::findClass(const char *className, JNIEnv *env) } if (clazz != 0) - cachedClasses->insert(classDotEnc, clazz); + cachedClasses->insert(key, clazz); } if (clazz == 0) // We didn't get an env. pointer or we got one with the WRONG class loader... - clazz = loadClassDotEnc(classDotEnc, QJNIEnvironmentPrivate()); + clazz = loadClass(classDotEnc, QJNIEnvironmentPrivate(), true); return clazz; } @@ -319,11 +341,12 @@ QJNIObjectPrivate::QJNIObjectPrivate(const char *className) : d(new QJNIObjectData()) { QJNIEnvironmentPrivate env; - d->m_jclass = loadClass(className, env); + d->m_className = toBinaryEncClassName(className); + d->m_jclass = loadClass(d->m_className, env, true); d->m_own_jclass = false; if (d->m_jclass) { // get default constructor - jmethodID constructorId = getCachedMethodID(env, d->m_jclass, "", "()V"); + jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "", "()V"); if (constructorId) { jobject obj = env->NewObject(d->m_jclass, constructorId); if (obj) { @@ -338,10 +361,11 @@ QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, ... : d(new QJNIObjectData()) { QJNIEnvironmentPrivate env; - d->m_jclass = loadClass(className, env); + d->m_className = toBinaryEncClassName(className); + d->m_jclass = loadClass(d->m_className, env, true); d->m_own_jclass = false; if (d->m_jclass) { - jmethodID constructorId = getCachedMethodID(env, d->m_jclass, "", sig); + jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "", sig); if (constructorId) { va_list args; va_start(args, sig); @@ -359,10 +383,11 @@ QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, con : d(new QJNIObjectData()) { QJNIEnvironmentPrivate env; - d->m_jclass = loadClass(className, env); + d->m_className = toBinaryEncClassName(className); + d->m_jclass = loadClass(d->m_className, env, true); d->m_own_jclass = false; if (d->m_jclass) { - jmethodID constructorId = getCachedMethodID(env, d->m_jclass, "", sig); + jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "", sig); if (constructorId) { jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); if (obj) { @@ -380,7 +405,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz) d->m_jclass = static_cast(env->NewGlobalRef(clazz)); if (d->m_jclass) { // get default constructor - jmethodID constructorId = getCachedMethodID(env, d->m_jclass, "", "()V"); + jmethodID constructorId = getMethodID(env, d->m_jclass, "", "()V"); if (constructorId) { jobject obj = env->NewObject(d->m_jclass, constructorId); if (obj) { @@ -398,7 +423,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz, const char *sig, ...) if (clazz) { d->m_jclass = static_cast(env->NewGlobalRef(clazz)); if (d->m_jclass) { - jmethodID constructorId = getCachedMethodID(env, d->m_jclass, "", sig); + jmethodID constructorId = getMethodID(env, d->m_jclass, "", sig); if (constructorId) { va_list args; va_start(args, sig); @@ -420,7 +445,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz, const char *sig, const QVaLis if (clazz) { d->m_jclass = static_cast(env->NewGlobalRef(clazz)); if (d->m_jclass) { - jmethodID constructorId = getCachedMethodID(env, d->m_jclass, "", sig); + jmethodID constructorId = getMethodID(env, d->m_jclass, "", sig); if (constructorId) { jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); if (obj) { @@ -440,15 +465,15 @@ QJNIObjectPrivate::QJNIObjectPrivate(jobject obj) QJNIEnvironmentPrivate env; d->m_jobject = env->NewGlobalRef(obj); - jclass objectClass = env->GetObjectClass(d->m_jobject); - d->m_jclass = static_cast(env->NewGlobalRef(objectClass)); - env->DeleteLocalRef(objectClass); + jclass cls = env->GetObjectClass(obj); + d->m_jclass = static_cast(env->NewGlobalRef(cls)); + env->DeleteLocalRef(cls); } template <> void QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { env->CallVoidMethodV(d->m_jobject, id, args); } @@ -468,7 +493,7 @@ jboolean QJNIObjectPrivate::callMethodV(const char *methodName, const { QJNIEnvironmentPrivate env; jboolean res = 0; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallBooleanMethodV(d->m_jobject, id, args); } @@ -490,7 +515,7 @@ jbyte QJNIObjectPrivate::callMethodV(const char *methodName, const char * { QJNIEnvironmentPrivate env; jbyte res = 0; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallByteMethodV(d->m_jobject, id, args); } @@ -512,7 +537,7 @@ jchar QJNIObjectPrivate::callMethodV(const char *methodName, const char * { QJNIEnvironmentPrivate env; jchar res = 0; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallCharMethodV(d->m_jobject, id, args); } @@ -534,7 +559,7 @@ jshort QJNIObjectPrivate::callMethodV(const char *methodName, const char { QJNIEnvironmentPrivate env; jshort res = 0; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallShortMethodV(d->m_jobject, id, args); } @@ -556,7 +581,7 @@ jint QJNIObjectPrivate::callMethodV(const char *methodName, const char *si { QJNIEnvironmentPrivate env; jint res = 0; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallIntMethodV(d->m_jobject, id, args); } @@ -578,7 +603,7 @@ jlong QJNIObjectPrivate::callMethodV(const char *methodName, const char * { QJNIEnvironmentPrivate env; jlong res = 0; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallLongMethodV(d->m_jobject, id, args); } @@ -600,7 +625,7 @@ jfloat QJNIObjectPrivate::callMethodV(const char *methodName, const char { QJNIEnvironmentPrivate env; jfloat res = 0.f; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallFloatMethodV(d->m_jobject, id, args); } @@ -622,7 +647,7 @@ jdouble QJNIObjectPrivate::callMethodV(const char *methodName, const ch { QJNIEnvironmentPrivate env; jdouble res = 0.; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallDoubleMethodV(d->m_jobject, id, args); } @@ -702,7 +727,7 @@ void QJNIObjectPrivate::callStaticMethodV(const char *className, QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { env->CallStaticVoidMethodV(clazz, id, args); } @@ -728,7 +753,7 @@ void QJNIObjectPrivate::callStaticMethodV(jclass clazz, va_list args) { QJNIEnvironmentPrivate env; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { env->CallStaticVoidMethodV(clazz, id, args); } @@ -756,7 +781,7 @@ jboolean QJNIObjectPrivate::callStaticMethodV(const char *className, jboolean res = 0; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticBooleanMethodV(clazz, id, args); } @@ -786,7 +811,7 @@ jboolean QJNIObjectPrivate::callStaticMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jboolean res = 0; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticBooleanMethodV(clazz, id, args); } @@ -817,7 +842,7 @@ jbyte QJNIObjectPrivate::callStaticMethodV(const char *className, jbyte res = 0; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticByteMethodV(clazz, id, args); } @@ -847,7 +872,7 @@ jbyte QJNIObjectPrivate::callStaticMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jbyte res = 0; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticByteMethodV(clazz, id, args); } @@ -878,7 +903,7 @@ jchar QJNIObjectPrivate::callStaticMethodV(const char *className, jchar res = 0; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticCharMethodV(clazz, id, args); } @@ -908,7 +933,7 @@ jchar QJNIObjectPrivate::callStaticMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jchar res = 0; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticCharMethodV(clazz, id, args); } @@ -939,7 +964,7 @@ jshort QJNIObjectPrivate::callStaticMethodV(const char *className, jshort res = 0; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticShortMethodV(clazz, id, args); } @@ -969,7 +994,7 @@ jshort QJNIObjectPrivate::callStaticMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jshort res = 0; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticShortMethodV(clazz, id, args); } @@ -1000,7 +1025,7 @@ jint QJNIObjectPrivate::callStaticMethodV(const char *className, jint res = 0; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticIntMethodV(clazz, id, args); } @@ -1030,7 +1055,7 @@ jint QJNIObjectPrivate::callStaticMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jint res = 0; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticIntMethodV(clazz, id, args); } @@ -1061,7 +1086,7 @@ jlong QJNIObjectPrivate::callStaticMethodV(const char *className, jlong res = 0; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticLongMethodV(clazz, id, args); } @@ -1091,7 +1116,7 @@ jlong QJNIObjectPrivate::callStaticMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jlong res = 0; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticLongMethodV(clazz, id, args); } @@ -1122,7 +1147,7 @@ jfloat QJNIObjectPrivate::callStaticMethodV(const char *className, jfloat res = 0.f; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticFloatMethodV(clazz, id, args); } @@ -1152,7 +1177,7 @@ jfloat QJNIObjectPrivate::callStaticMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jfloat res = 0.f; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticFloatMethodV(clazz, id, args); } @@ -1183,7 +1208,7 @@ jdouble QJNIObjectPrivate::callStaticMethodV(const char *className, jdouble res = 0.; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticDoubleMethodV(clazz, id, args); } @@ -1213,7 +1238,7 @@ jdouble QJNIObjectPrivate::callStaticMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jdouble res = 0.; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticDoubleMethodV(clazz, id, args); } @@ -1348,7 +1373,7 @@ QJNIObjectPrivate QJNIObjectPrivate::callObjectMethodV(const char *methodName, { QJNIEnvironmentPrivate env; jobject res = 0; - jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); if (id) { res = env->CallObjectMethodV(d->m_jobject, id, args); if (res && env->ExceptionCheck()) @@ -1428,7 +1453,7 @@ QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethodV(const char *classNa jobject res = 0; jclass clazz = loadClass(className, env); if (clazz) { - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); if (id) { res = env->CallStaticObjectMethodV(clazz, id, args); if (res && env->ExceptionCheck()) @@ -1460,7 +1485,7 @@ QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethodV(jclass clazz, { QJNIEnvironmentPrivate env; jobject res = 0; - jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); + jmethodID id = getMethodID(env, clazz, methodName, sig, true); if (id) { res = env->CallStaticObjectMethodV(clazz, id, args); if (res && env->ExceptionCheck()) @@ -1489,7 +1514,7 @@ jboolean QJNIObjectPrivate::getField(const char *fieldName) const { QJNIEnvironmentPrivate env; jboolean res = 0; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "Z"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "Z"); if (id) res = env->GetBooleanField(d->m_jobject, id); @@ -1501,7 +1526,7 @@ jbyte QJNIObjectPrivate::getField(const char *fieldName) const { QJNIEnvironmentPrivate env; jbyte res = 0; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "B"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "B"); if (id) res = env->GetByteField(d->m_jobject, id); @@ -1513,7 +1538,7 @@ jchar QJNIObjectPrivate::getField(const char *fieldName) const { QJNIEnvironmentPrivate env; jchar res = 0; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "C"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "C"); if (id) res = env->GetCharField(d->m_jobject, id); @@ -1525,7 +1550,7 @@ jshort QJNIObjectPrivate::getField(const char *fieldName) const { QJNIEnvironmentPrivate env; jshort res = 0; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "S"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "S"); if (id) res = env->GetShortField(d->m_jobject, id); @@ -1537,7 +1562,7 @@ jint QJNIObjectPrivate::getField(const char *fieldName) const { QJNIEnvironmentPrivate env; jint res = 0; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "I"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "I"); if (id) res = env->GetIntField(d->m_jobject, id); @@ -1549,7 +1574,7 @@ jlong QJNIObjectPrivate::getField(const char *fieldName) const { QJNIEnvironmentPrivate env; jlong res = 0; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "J"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "J"); if (id) res = env->GetLongField(d->m_jobject, id); @@ -1561,7 +1586,7 @@ jfloat QJNIObjectPrivate::getField(const char *fieldName) const { QJNIEnvironmentPrivate env; jfloat res = 0.f; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "F"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "F"); if (id) res = env->GetFloatField(d->m_jobject, id); @@ -1573,7 +1598,7 @@ jdouble QJNIObjectPrivate::getField(const char *fieldName) const { QJNIEnvironmentPrivate env; jdouble res = 0.; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "D"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "D"); if (id) res = env->GetDoubleField(d->m_jobject, id); @@ -1585,7 +1610,7 @@ jboolean QJNIObjectPrivate::getStaticField(jclass clazz, const char *f { QJNIEnvironmentPrivate env; jboolean res = 0; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "Z", true); + jfieldID id = getFieldID(env, clazz, fieldName, "Z", true); if (id) res = env->GetStaticBooleanField(clazz, id); @@ -1596,12 +1621,15 @@ template <> jboolean QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) { QJNIEnvironmentPrivate env; - jboolean res = 0; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticField(clazz, fieldName); + if (clazz == 0) + return 0; - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "Z", true); + if (id == 0) + return 0; + + return env->GetStaticBooleanField(clazz, id); } template <> @@ -1609,7 +1637,7 @@ jbyte QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldNa { QJNIEnvironmentPrivate env; jbyte res = 0; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "B", true); + jfieldID id = getFieldID(env, clazz, fieldName, "B", true); if (id) res = env->GetStaticByteField(clazz, id); @@ -1620,12 +1648,15 @@ template <> jbyte QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) { QJNIEnvironmentPrivate env; - jbyte res = 0; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticField(clazz, fieldName); + if (clazz == 0) + return 0; - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "B", true); + if (id == 0) + return 0; + + return env->GetStaticByteField(clazz, id); } template <> @@ -1633,7 +1664,7 @@ jchar QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldNa { QJNIEnvironmentPrivate env; jchar res = 0; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "C", true); + jfieldID id = getFieldID(env, clazz, fieldName, "C", true); if (id) res = env->GetStaticCharField(clazz, id); @@ -1644,12 +1675,15 @@ template <> jchar QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) { QJNIEnvironmentPrivate env; - jchar res = 0; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticField(clazz, fieldName); + if (clazz == 0) + return 0; - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "C", true); + if (id == 0) + return 0; + + return env->GetStaticCharField(clazz, id); } template <> @@ -1657,7 +1691,7 @@ jshort QJNIObjectPrivate::getStaticField(jclass clazz, const char *field { QJNIEnvironmentPrivate env; jshort res = 0; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "S", true); + jfieldID id = getFieldID(env, clazz, fieldName, "S", true); if (id) res = env->GetStaticShortField(clazz, id); @@ -1668,12 +1702,15 @@ template <> jshort QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) { QJNIEnvironmentPrivate env; - jshort res = 0; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticField(clazz, fieldName); + if (clazz == 0) + return 0; - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "S", true); + if (id == 0) + return 0; + + return env->GetStaticShortField(clazz, id); } template <> @@ -1681,7 +1718,7 @@ jint QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName { QJNIEnvironmentPrivate env; jint res = 0; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "I", true); + jfieldID id = getFieldID(env, clazz, fieldName, "I", true); if (id) res = env->GetStaticIntField(clazz, id); @@ -1692,12 +1729,15 @@ template <> jint QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) { QJNIEnvironmentPrivate env; - jint res = 0; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticField(clazz, fieldName); + if (clazz == 0) + return 0; - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "I", true); + if (id == 0) + return 0; + + return env->GetStaticIntField(clazz, id); } template <> @@ -1705,7 +1745,7 @@ jlong QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldNa { QJNIEnvironmentPrivate env; jlong res = 0; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "J", true); + jfieldID id = getFieldID(env, clazz, fieldName, "J", true); if (id) res = env->GetStaticLongField(clazz, id); @@ -1716,12 +1756,15 @@ template <> jlong QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) { QJNIEnvironmentPrivate env; - jlong res = 0; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticField(clazz, fieldName); + if (clazz == 0) + return 0; - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "J", true); + if (id == 0) + return 0; + + return env->GetStaticLongField(clazz, id); } template <> @@ -1729,7 +1772,7 @@ jfloat QJNIObjectPrivate::getStaticField(jclass clazz, const char *field { QJNIEnvironmentPrivate env; jfloat res = 0.f; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "F", true); + jfieldID id = getFieldID(env, clazz, fieldName, "F", true); if (id) res = env->GetStaticFloatField(clazz, id); @@ -1740,12 +1783,15 @@ template <> jfloat QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) { QJNIEnvironmentPrivate env; - jfloat res = 0.f; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticField(clazz, fieldName); + if (clazz == 0) + return 0.f; - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "F", true); + if (id == 0) + return 0.f; + + return env->GetStaticFloatField(clazz, id); } template <> @@ -1753,7 +1799,7 @@ jdouble QJNIObjectPrivate::getStaticField(jclass clazz, const char *fie { QJNIEnvironmentPrivate env; jdouble res = 0.; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "D", true); + jfieldID id = getFieldID(env, clazz, fieldName, "D", true); if (id) res = env->GetStaticDoubleField(clazz, id); @@ -1764,12 +1810,15 @@ template <> jdouble QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) { QJNIEnvironmentPrivate env; - jdouble res = 0.; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticField(clazz, fieldName); + if (clazz == 0) + return 0.; - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "D", true); + if (id == 0) + return 0.; + + return env->GetStaticDoubleField(clazz, id); } QJNIObjectPrivate QJNIObjectPrivate::getObjectField(const char *fieldName, @@ -1777,7 +1826,7 @@ QJNIObjectPrivate QJNIObjectPrivate::getObjectField(const char *fieldName, { QJNIEnvironmentPrivate env; jobject res = 0; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, sig); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); if (id) { res = env->GetObjectField(d->m_jobject, id); if (res && env->ExceptionCheck()) @@ -1794,12 +1843,21 @@ QJNIObjectPrivate QJNIObjectPrivate::getStaticObjectField(const char *className, const char *sig) { QJNIEnvironmentPrivate env; - QJNIObjectPrivate res; jclass clazz = loadClass(className, env); - if (clazz) - res = getStaticObjectField(clazz, fieldName, sig); + if (clazz == 0) + return QJNIObjectPrivate(); - return res; + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, sig, true); + if (id == 0) + return QJNIObjectPrivate(); + + jobject res = env->GetStaticObjectField(clazz, id); + if (res && env->ExceptionCheck()) + res = 0; + + QJNIObjectPrivate obj(res); + env->DeleteLocalRef(res); + return obj; } QJNIObjectPrivate QJNIObjectPrivate::getStaticObjectField(jclass clazz, @@ -1808,7 +1866,7 @@ QJNIObjectPrivate QJNIObjectPrivate::getStaticObjectField(jclass clazz, { QJNIEnvironmentPrivate env; jobject res = 0; - jfieldID id = getCachedFieldID(env, clazz, fieldName, sig, true); + jfieldID id = getFieldID(env, clazz, fieldName, sig, true); if (id) { res = env->GetStaticObjectField(clazz, id); if (res && env->ExceptionCheck()) @@ -1824,7 +1882,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jboolean value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "Z"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "Z"); if (id) env->SetBooleanField(d->m_jobject, id, value); @@ -1834,7 +1892,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jbyte value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "B"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "B"); if (id) env->SetByteField(d->m_jobject, id, value); @@ -1844,7 +1902,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jchar value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "C"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "C"); if (id) env->SetCharField(d->m_jobject, id, value); @@ -1854,7 +1912,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jshort value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "S"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "S"); if (id) env->SetShortField(d->m_jobject, id, value); @@ -1864,7 +1922,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jint value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "I"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "I"); if (id) env->SetIntField(d->m_jobject, id, value); @@ -1874,7 +1932,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jlong value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "J"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "J"); if (id) env->SetLongField(d->m_jobject, id, value); @@ -1884,7 +1942,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jfloat value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "F"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "F"); if (id) env->SetFloatField(d->m_jobject, id, value); @@ -1894,7 +1952,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jdouble value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "D"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "D"); if (id) env->SetDoubleField(d->m_jobject, id, value); @@ -1904,7 +1962,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jbooleanArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "[Z"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[Z"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1914,7 +1972,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jbyteArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "[B"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[B"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1924,7 +1982,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jcharArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "[C"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[C"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1934,7 +1992,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jshortArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "[S"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[S"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1944,7 +2002,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jintArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "[I"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[I"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1954,7 +2012,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jlongArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "[J"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[J"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1964,7 +2022,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jfloatArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "[F"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[F"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1974,7 +2032,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jdoubleArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "[D"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[D"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1984,7 +2042,7 @@ template <> void QJNIObjectPrivate::setField(const char *fieldName, jstring value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, "Ljava/lang/String;"); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "Ljava/lang/String;"); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -1996,7 +2054,7 @@ void QJNIObjectPrivate::setField(const char *fieldName, jobject value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, sig); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -2008,7 +2066,7 @@ void QJNIObjectPrivate::setField(const char *fieldName, jobjectArray value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, d->m_jclass, fieldName, sig); + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); if (id) env->SetObjectField(d->m_jobject, id, value); @@ -2020,7 +2078,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jboolean value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "Z", true); + jfieldID id = getFieldID(env, clazz, fieldName, "Z", true); if (id) env->SetStaticBooleanField(clazz, id, value); } @@ -2032,8 +2090,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "Z", true); + if (id == 0) + return; + + env->SetStaticBooleanField(clazz, id, value); } template <> @@ -2042,7 +2106,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jbyte value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "B", true); + jfieldID id = getFieldID(env, clazz, fieldName, "B", true); if (id) env->SetStaticByteField(clazz, id, value); } @@ -2054,8 +2118,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "B", true); + if (id == 0) + return; + + env->SetStaticByteField(clazz, id, value); } template <> @@ -2064,7 +2134,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jchar value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "C", true); + jfieldID id = getFieldID(env, clazz, fieldName, "C", true); if (id) env->SetStaticCharField(clazz, id, value); } @@ -2076,8 +2146,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "C", true); + if (id == 0) + return; + + env->SetStaticCharField(clazz, id, value); } template <> @@ -2086,7 +2162,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jshort value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "S", true); + jfieldID id = getFieldID(env, clazz, fieldName, "S", true); if (id) env->SetStaticShortField(clazz, id, value); } @@ -2098,8 +2174,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "S", true); + if (id == 0) + return; + + env->SetStaticShortField(clazz, id, value); } template <> @@ -2108,7 +2190,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jint value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "I", true); + jfieldID id = getFieldID(env, clazz, fieldName, "I", true); if (id) env->SetStaticIntField(clazz, id, value); } @@ -2120,8 +2202,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "I", true); + if (id == 0) + return; + + env->SetStaticIntField(clazz, id, value); } template <> @@ -2130,7 +2218,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jlong value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "J", true); + jfieldID id = getFieldID(env, clazz, fieldName, "J", true); if (id) env->SetStaticLongField(clazz, id, value); } @@ -2142,8 +2230,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "J", true); + if (id == 0) + return; + + env->SetStaticLongField(clazz, id, value); } template <> @@ -2152,7 +2246,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jfloat value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "F", true); + jfieldID id = getFieldID(env, clazz, fieldName, "F", true); if (id) env->SetStaticFloatField(clazz, id, value); } @@ -2164,8 +2258,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "F", true); + if (id == 0) + return; + + env->SetStaticFloatField(clazz, id, value); } template <> @@ -2174,7 +2274,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jdouble value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, "D", true); + jfieldID id = getFieldID(env, clazz, fieldName, "D", true); if (id) env->SetStaticDoubleField(clazz, id, value); } @@ -2186,8 +2286,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "D", true); + if (id == 0) + return; + + env->SetStaticDoubleField(clazz, id, value); } template <> @@ -2197,7 +2303,7 @@ void QJNIObjectPrivate::setStaticField(jclass clazz, jobject value) { QJNIEnvironmentPrivate env; - jfieldID id = getCachedFieldID(env, clazz, fieldName, sig, true); + jfieldID id = getFieldID(env, clazz, fieldName, sig, true); if (id) env->SetStaticObjectField(clazz, id, value); } @@ -2210,8 +2316,14 @@ void QJNIObjectPrivate::setStaticField(const char *className, { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); - if (clazz) - setStaticField(clazz, fieldName, sig, value); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, sig, true); + if (id == 0) + return; + + env->SetStaticObjectField(clazz, id, value); } QJNIObjectPrivate QJNIObjectPrivate::fromString(const QString &string) diff --git a/src/corelib/kernel/qjni_p.h b/src/corelib/kernel/qjni_p.h index ae9c7c3a7e..1c23f2ab76 100644 --- a/src/corelib/kernel/qjni_p.h +++ b/src/corelib/kernel/qjni_p.h @@ -82,6 +82,7 @@ public: jobject m_jobject; jclass m_jclass; bool m_own_jclass; + QByteArray m_className; }; class Q_CORE_EXPORT QJNIObjectPrivate diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 1e2a860d8c..1b214e9f74 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1357,12 +1357,16 @@ namespace QtPrivate enum { Value = sizeof(checkType(static_cast(0))) == sizeof(yes_type) }; }; + template + struct IsGadgetHelper { enum { Value = false }; }; + template - struct IsGadgetHelper + struct IsGadgetHelper { - template static typename X::QtGadgetHelper *checkType(X*); - static char checkType(void*); - enum { Value = sizeof(checkType(static_cast(0))) == sizeof(void*) }; + template + static char checkType(void (X::*)()); + static void *checkType(void (T::*)()); + enum { Value = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *) }; }; @@ -1381,6 +1385,7 @@ QT_WARNING_DISABLE_CLANG("-Wlocal-type-template-args") // qt_getEnumMetaObject(T) which returns 'char' enum { Value = sizeof(qt_getEnumMetaObject(declval())) == sizeof(QMetaObject*) }; }; + template<> struct IsQEnumHelper { enum { Value = false }; }; QT_WARNING_POP template @@ -1768,7 +1773,7 @@ template struct QMetaTypeIdQObject { enum { - Defined = 1 + Defined = QtPrivate::is_default_constructible::value }; static int qt_metatype_id() diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index 31e8a670e9..4d01264906 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -172,6 +172,7 @@ private: \ #define Q_GADGET \ public: \ static const QMetaObject staticMetaObject; \ + void qt_check_for_QGADGET_macro(); \ typedef void QtGadgetHelper; \ private: \ Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp index 4d37368b2e..5cc54b1def 100644 --- a/src/corelib/kernel/qsharedmemory_win.cpp +++ b/src/corelib/kernel/qsharedmemory_win.cpp @@ -163,6 +163,7 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) #if defined(Q_OS_WINPHONE) Q_UNIMPLEMENTED(); Q_UNUSED(mode) + Q_UNUSED(permissions) memory = 0; #elif defined(Q_OS_WINRT) memory = (void *)MapViewOfFileFromApp(handle(), permissions, 0, 0); diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index ed856a538c..3206ff66e3 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -54,12 +54,12 @@ QMimeTypePrivate::QMimeTypePrivate() {} QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other) - : name(other.d->name), + : loaded(other.d->loaded), + name(other.d->name), localeComments(other.d->localeComments), genericIconName(other.d->genericIconName), iconName(other.d->iconName), - globPatterns(other.d->globPatterns), - loaded(other.d->loaded) + globPatterns(other.d->globPatterns) {} void QMimeTypePrivate::clear() diff --git a/src/corelib/mimetypes/qmimetype_p.h b/src/corelib/mimetypes/qmimetype_p.h index bf533bbcb0..2161dd8901 100644 --- a/src/corelib/mimetypes/qmimetype_p.h +++ b/src/corelib/mimetypes/qmimetype_p.h @@ -66,12 +66,12 @@ public: void addGlobPattern(const QString &pattern); + bool loaded; // QSharedData leaves a 4 byte gap, so don't put 8 byte members first QString name; LocaleHash localeComments; QString genericIconName; QString iconName; QStringList globPatterns; - bool loaded; }; QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp index f128acd54e..81b38ea4c4 100644 --- a/src/corelib/statemachine/qabstracttransition.cpp +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -101,7 +101,35 @@ QT_BEGIN_NAMESPACE parallel group state. */ +/*! + \property QAbstractTransition::transitionType + + \brief indicates whether this transition is an internal transition, or an external transition. + + Internal and external transitions behave the same, except for the case of a transition whose + source state is a compound state and whose target(s) is a descendant of the source. In such a + case, an internal transition will not exit and re-enter its source state, while an external one + will. + + By default, the type is an external transition. +*/ + +/*! + \enum QAbstractTransition::TransitionType + + This enum specifies the kind of transition. By default, the type is an external transition. + + \value ExternalTransition Any state that is the source state of a transition (which is not a + target-less transition) is left, and re-entered when necessary. + \value InternalTransition If the target state of a transition is a sub-state of a compound state, + and that compound state is the source state, an internal transition will + not leave the source state. + + \sa QAbstractTransition::transitionType +*/ + QAbstractTransitionPrivate::QAbstractTransitionPrivate() + : transitionType(QAbstractTransition::ExternalTransition) { } @@ -248,6 +276,24 @@ void QAbstractTransition::setTargetStates(const QList &targets) emit targetStatesChanged(QPrivateSignal()); } +/*! + Returns the type of the transition. +*/ +QAbstractTransition::TransitionType QAbstractTransition::transitionType() const +{ + Q_D(const QAbstractTransition); + return d->transitionType; +} + +/*! + Sets the type of the transition to \a type. +*/ +void QAbstractTransition::setTransitionType(TransitionType type) +{ + Q_D(QAbstractTransition); + d->transitionType = type; +} + /*! Returns the state machine that this transition is part of, or 0 if the transition is not part of a state machine. diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h index 768a364a4b..bf32b3e825 100644 --- a/src/corelib/statemachine/qabstracttransition.h +++ b/src/corelib/statemachine/qabstracttransition.h @@ -59,7 +59,14 @@ class Q_CORE_EXPORT QAbstractTransition : public QObject Q_PROPERTY(QState* sourceState READ sourceState) Q_PROPERTY(QAbstractState* targetState READ targetState WRITE setTargetState NOTIFY targetStateChanged) Q_PROPERTY(QList targetStates READ targetStates WRITE setTargetStates NOTIFY targetStatesChanged) + Q_PROPERTY(TransitionType transitionType READ transitionType WRITE setTransitionType) public: + enum TransitionType { + ExternalTransition, + InternalTransition + }; + Q_ENUM(TransitionType) + QAbstractTransition(QState *sourceState = 0); virtual ~QAbstractTransition(); @@ -69,6 +76,9 @@ public: QList targetStates() const; void setTargetStates(const QList &targets); + TransitionType transitionType() const; + void setTransitionType(TransitionType type); + QStateMachine *machine() const; #ifndef QT_NO_ANIMATION diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h index d89d057497..4b0644acd9 100644 --- a/src/corelib/statemachine/qabstracttransition_p.h +++ b/src/corelib/statemachine/qabstracttransition_p.h @@ -73,6 +73,7 @@ public: void emitTriggered(); QList > targetStates; + QAbstractTransition::TransitionType transitionType; #ifndef QT_NO_ANIMATION QList animations; diff --git a/src/corelib/statemachine/qeventtransition_p.h b/src/corelib/statemachine/qeventtransition_p.h index 64ab945187..59b0fcb30f 100644 --- a/src/corelib/statemachine/qeventtransition_p.h +++ b/src/corelib/statemachine/qeventtransition_p.h @@ -61,8 +61,8 @@ public: void unregister(); void maybeRegister(); - bool registered; QObject *object; + bool registered; QEvent::Type eventType; }; diff --git a/src/corelib/statemachine/qstate_p.h b/src/corelib/statemachine/qstate_p.h index 28bb176b56..2ce0c13522 100644 --- a/src/corelib/statemachine/qstate_p.h +++ b/src/corelib/statemachine/qstate_p.h @@ -103,8 +103,8 @@ public: QAbstractState *initialState; QState::ChildMode childMode; mutable bool childStatesListNeedsRefresh; - mutable QList childStatesList; mutable bool transitionsListNeedsRefresh; + mutable QList childStatesList; mutable QList transitionsList; #ifndef QT_NO_PROPERTIES diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index a8d07602b6..3a1a852ef5 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -177,6 +177,100 @@ QT_BEGIN_NAMESPACE // #define QSTATEMACHINE_DEBUG // #define QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG +struct CalculationCache { + struct TransitionInfo { + QList effectiveTargetStates; + QSet exitSet; + QAbstractState *transitionDomain; + + bool effectiveTargetStatesIsKnown: 1; + bool exitSetIsKnown : 1; + bool transitionDomainIsKnown : 1; + + TransitionInfo() + : transitionDomain(0) + , effectiveTargetStatesIsKnown(false) + , exitSetIsKnown(false) + , transitionDomainIsKnown(false) + {} + }; + + typedef QHash TransitionInfoCache; + TransitionInfoCache cache; + + bool effectiveTargetStates(QAbstractTransition *t, QList *targets) const + { + Q_ASSERT(targets); + + TransitionInfoCache::const_iterator cacheIt = cache.find(t); + if (cacheIt == cache.end() || !cacheIt->effectiveTargetStatesIsKnown) + return false; + + *targets = cacheIt->effectiveTargetStates; + return true; + } + + void insert(QAbstractTransition *t, const QList &targets) + { + TransitionInfoCache::iterator cacheIt = cache.find(t); + TransitionInfo &ti = cacheIt == cache.end() + ? *cache.insert(t, TransitionInfo()) + : *cacheIt; + + Q_ASSERT(!ti.effectiveTargetStatesIsKnown); + ti.effectiveTargetStates = targets; + ti.effectiveTargetStatesIsKnown = true; + } + + bool exitSet(QAbstractTransition *t, QSet *exits) const + { + Q_ASSERT(exits); + + TransitionInfoCache::const_iterator cacheIt = cache.find(t); + if (cacheIt == cache.end() || !cacheIt->exitSetIsKnown) + return false; + + *exits = cacheIt->exitSet; + return true; + } + + void insert(QAbstractTransition *t, const QSet &exits) + { + TransitionInfoCache::iterator cacheIt = cache.find(t); + TransitionInfo &ti = cacheIt == cache.end() + ? *cache.insert(t, TransitionInfo()) + : *cacheIt; + + Q_ASSERT(!ti.exitSetIsKnown); + ti.exitSet = exits; + ti.exitSetIsKnown = true; + } + + bool transitionDomain(QAbstractTransition *t, QAbstractState **domain) const + { + Q_ASSERT(domain); + + TransitionInfoCache::const_iterator cacheIt = cache.find(t); + if (cacheIt == cache.end() || !cacheIt->transitionDomainIsKnown) + return false; + + *domain = cacheIt->transitionDomain; + return true; + } + + void insert(QAbstractTransition *t, QAbstractState *domain) + { + TransitionInfoCache::iterator cacheIt = cache.find(t); + TransitionInfo &ti = cacheIt == cache.end() + ? *cache.insert(t, TransitionInfo()) + : *cacheIt; + + Q_ASSERT(!ti.transitionDomainIsKnown); + ti.transitionDomain = domain; + ti.transitionDomainIsKnown = true; + } +}; + /* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : function isDescendant(state1, state2) @@ -205,6 +299,17 @@ static bool containsDecendantOf(const QSet &states, const QAbs return false; } +static int descendantDepth(const QAbstractState *state, const QAbstractState *ancestor) +{ + int depth = 0; + for (const QAbstractState *it = state; it != 0; it = it->parentState()) { + if (it == ancestor) + break; + ++depth; + } + return depth; +} + /* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ : function getProperAncestors(state1, state2) @@ -245,8 +350,14 @@ function getEffectiveTargetStates(transition) targets.add(s) return targets */ -static QSet getEffectiveTargetStates(QAbstractTransition *transition) +static QList getEffectiveTargetStates(QAbstractTransition *transition, CalculationCache *cache) { + Q_ASSERT(cache); + + QList targetsList; + if (cache->effectiveTargetStates(transition, &targetsList)) + return targetsList; + QSet targets; foreach (QAbstractState *s, transition->targetStates()) { if (QHistoryState *historyState = QStateMachinePrivate::toHistoryState(s)) { @@ -266,7 +377,10 @@ static QSet getEffectiveTargetStates(QAbstractTransition *tran targets.insert(s); } } - return targets; + + targetsList = targets.toList(); + cache->insert(transition, targetsList); + return targetsList; } template @@ -348,10 +462,25 @@ static int indexOfDescendant(QState *s, QAbstractState *desc) bool QStateMachinePrivate::transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2) { QState *s1 = t1->sourceState(), *s2 = t2->sourceState(); - if (s1 == s2) - return QStatePrivate::get(s1)->transitions().indexOf(t1) < QStatePrivate::get(s2)->transitions().indexOf(t2); - else - return stateEntryLessThan(t1->sourceState(), t2->sourceState()); + if (s1 == s2) { + QList transitions = QStatePrivate::get(s1)->transitions(); + return transitions.indexOf(t1) < transitions.indexOf(t2); + } else if (isDescendant(s1, s2)) { + return true; + } else if (isDescendant(s2, s1)) { + return false; + } else { + Q_ASSERT(s1->machine() != 0); + QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine()); + QState *lca = mach->findLCA(QList() << s1 << s2); + Q_ASSERT(lca != 0); + int s1Depth = descendantDepth(s1, lca); + int s2Depth = descendantDepth(s2, lca); + if (s1Depth == s2Depth) + return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2)); + else + return s1Depth > s2Depth; + } } bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2) @@ -417,8 +546,9 @@ QState *QStateMachinePrivate::findLCCA(const QList &states) con return findLCA(states, true); } -QList QStateMachinePrivate::selectTransitions(QEvent *event) +QList QStateMachinePrivate::selectTransitions(QEvent *event, CalculationCache *cache) { + Q_ASSERT(cache); Q_Q(const QStateMachine); QVarLengthArray configuration_sorted; @@ -453,7 +583,7 @@ QList QStateMachinePrivate::selectTransitions(QEvent *even } if (!enabledTransitions.isEmpty()) { - removeConflictingTransitions(enabledTransitions); + removeConflictingTransitions(enabledTransitions, cache); #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": enabled transitions after removing conflicts:" << enabledTransitions; #endif @@ -486,15 +616,20 @@ function removeConflictingTransitions(enabledTransitions): Note: the implementation below does not build the transitionsToRemove, but removes them in-place. */ -void QStateMachinePrivate::removeConflictingTransitions(QList &enabledTransitions) +void QStateMachinePrivate::removeConflictingTransitions(QList &enabledTransitions, CalculationCache *cache) { + Q_ASSERT(cache); + + if (enabledTransitions.size() < 2) + return; // There is no transition to conflict with. + QList filteredTransitions; filteredTransitions.reserve(enabledTransitions.size()); std::sort(enabledTransitions.begin(), enabledTransitions.end(), transitionStateEntryLessThan); foreach (QAbstractTransition *t1, enabledTransitions) { bool t1Preempted = false; - QSet exitSetT1 = computeExitSet_Unordered(QList() << t1); + QSet exitSetT1 = computeExitSet_Unordered(t1, cache); QList::iterator t2It = filteredTransitions.begin(); while (t2It != filteredTransitions.end()) { QAbstractTransition *t2 = *t2It; @@ -505,8 +640,8 @@ void QStateMachinePrivate::removeConflictingTransitions(QList exitSetT2 = computeExitSet_Unordered(QList() << t2); - if (!exitSetT1.intersects(exitSetT2)) { + QSet exitSetT2 = computeExitSet_Unordered(t2, cache); + if (exitSetT1.intersect(exitSetT2).isEmpty()) { // No conflict, no cry. Next patient please. ++t2It; } else { @@ -529,17 +664,20 @@ void QStateMachinePrivate::removeConflictingTransitions(QList &enabledTransitions) +void QStateMachinePrivate::microstep(QEvent *event, const QList &enabledTransitions, + CalculationCache *cache) { + Q_ASSERT(cache); + #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ')'; qDebug() << q_func() << ": configuration before exiting states:" << configuration; #endif - QList exitedStates = computeExitSet(enabledTransitions); + QList exitedStates = computeExitSet(enabledTransitions, cache); QHash pendingRestorables = computePendingRestorables(exitedStates); QSet statesForDefaultEntry; - QList enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry); + QList enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry, cache); #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": computed exit set:" << exitedStates; @@ -598,42 +736,61 @@ function computeExitSet(transitions) statesToExit.add(s) return statesToExit */ -QList QStateMachinePrivate::computeExitSet(const QList &enabledTransitions) +QList QStateMachinePrivate::computeExitSet(const QList &enabledTransitions, + CalculationCache *cache) { - QList statesToExit_sorted = computeExitSet_Unordered(enabledTransitions).toList(); + Q_ASSERT(cache); + + QList statesToExit_sorted = computeExitSet_Unordered(enabledTransitions, cache).toList(); std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan); return statesToExit_sorted; } -QSet QStateMachinePrivate::computeExitSet_Unordered(const QList &enabledTransitions) +QSet QStateMachinePrivate::computeExitSet_Unordered(const QList &enabledTransitions, + CalculationCache *cache) { + Q_ASSERT(cache); + QSet statesToExit; - for (int i = 0; i < enabledTransitions.size(); ++i) { - QAbstractTransition *t = enabledTransitions.at(i); - QList effectiveTargetStates = getEffectiveTargetStates(t).toList(); - QAbstractState *domain = getTransitionDomain(t, effectiveTargetStates); - if (domain == Q_NULLPTR && !t->targetStates().isEmpty()) { - // So we didn't find the least common ancestor for the source and target states of the - // transition. If there were not target states, that would be fine: then the transition - // will fire any events or signals, but not exit the state. - // - // However, there are target states, so it's either a node without a parent (or parent's - // parent, etc), or the state belongs to a different state machine. Either way, this - // makes the state machine invalid. - if (error == QStateMachine::NoError) - setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState()); - QList lst = pendingErrorStates.toList(); - lst.prepend(t->sourceState()); + foreach (QAbstractTransition *t, enabledTransitions) + statesToExit.unite(computeExitSet_Unordered(t, cache)); + return statesToExit; +} - domain = findLCCA(lst); - Q_ASSERT(domain != 0); - } +QSet QStateMachinePrivate::computeExitSet_Unordered(QAbstractTransition *t, + CalculationCache *cache) +{ + Q_ASSERT(cache); - foreach (QAbstractState* s, configuration) { - if (isDescendant(s, domain)) - statesToExit.insert(s); - } + QSet statesToExit; + if (cache->exitSet(t, &statesToExit)) + return statesToExit; + + QList effectiveTargetStates = getEffectiveTargetStates(t, cache); + QAbstractState *domain = getTransitionDomain(t, effectiveTargetStates, cache); + if (domain == Q_NULLPTR && !t->targetStates().isEmpty()) { + // So we didn't find the least common ancestor for the source and target states of the + // transition. If there were not target states, that would be fine: then the transition + // will fire any events or signals, but not exit the state. + // + // However, there are target states, so it's either a node without a parent (or parent's + // parent, etc), or the state belongs to a different state machine. Either way, this + // makes the state machine invalid. + if (error == QStateMachine::NoError) + setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState()); + QList lst = pendingErrorStates.toList(); + lst.prepend(t->sourceState()); + + domain = findLCCA(lst); + Q_ASSERT(domain != 0); } + + foreach (QAbstractState* s, configuration) { + if (isDescendant(s, domain)) + statesToExit.insert(s); + } + + cache->insert(t, statesToExit); return statesToExit; } @@ -695,8 +852,11 @@ void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList QStateMachinePrivate::computeEntrySet(const QList &enabledTransitions, - QSet &statesForDefaultEntry) + QSet &statesForDefaultEntry, + CalculationCache *cache) { + Q_ASSERT(cache); + QSet statesToEnter; if (pendingErrorStates.isEmpty()) { foreach (QAbstractTransition *t, enabledTransitions) { @@ -704,8 +864,8 @@ QList QStateMachinePrivate::computeEntrySet(const QList effectiveTargetStates = getEffectiveTargetStates(t).toList(); - QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates); + QList effectiveTargetStates = getEffectiveTargetStates(t, cache); + QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates, cache); foreach (QAbstractState *s, effectiveTargetStates) { addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry); } @@ -742,33 +902,42 @@ function getTransitionDomain(t) else: return findLCCA([t.source].append(tstates)) */ -QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t, const QList &effectiveTargetStates) const +QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t, + const QList &effectiveTargetStates, + CalculationCache *cache) const { + Q_ASSERT(cache); + if (effectiveTargetStates.isEmpty()) return 0; -#if 0 - // Qt only has external transitions, so skip the special case for the internal transitions - if (QState *tSource = t->sourceState()) { - if (isCompound(tSource)) { - bool allDescendants = true; - foreach (QAbstractState *s, effectiveTargetStates) { - if (!isDescendant(s, tSource)) { - allDescendants = false; - break; - } - } + QAbstractState *domain = Q_NULLPTR; + if (cache->transitionDomain(t, &domain)) + return domain; - if (allDescendants) - return tSource; + if (t->transitionType() == QAbstractTransition::InternalTransition) { + if (QState *tSource = t->sourceState()) { + if (isCompound(tSource)) { + bool allDescendants = true; + foreach (QAbstractState *s, effectiveTargetStates) { + if (!isDescendant(s, tSource)) { + allDescendants = false; + break; + } + } + + if (allDescendants) + return tSource; + } } } -#endif QList states(effectiveTargetStates); if (QAbstractState *src = t->sourceState()) states.prepend(src); - return findLCCA(states); + domain = findLCCA(states); + cache->insert(t, domain); + return domain; } void QStateMachinePrivate::enterStates(QEvent *event, const QList &exitedStates_sorted, @@ -1676,6 +1845,8 @@ void QStateMachinePrivate::_q_start() registerMultiThreadedSignalTransitions(); + startupHook(); + #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": starting"; #endif @@ -1683,6 +1854,7 @@ void QStateMachinePrivate::_q_start() processingScheduled = true; // we call _q_process() below QList transitions; + CalculationCache calculationCache; QAbstractTransition *initialTransition = createInitialTransition(); transitions.append(initialTransition); @@ -1690,7 +1862,7 @@ void QStateMachinePrivate::_q_start() executeTransitionContent(&nullEvent, transitions); QList exitedStates = QList(); QSet statesForDefaultEntry; - QList enteredStates = computeEntrySet(transitions, statesForDefaultEntry); + QList enteredStates = computeEntrySet(transitions, statesForDefaultEntry, &calculationCache); QHash pendingRestorables; QHash > assignmentsForEnteredStates = computePropertyAssignments(enteredStates, pendingRestorables); @@ -1745,50 +1917,46 @@ void QStateMachinePrivate::_q_process() break; } QList enabledTransitions; + CalculationCache calculationCache; + QEvent *e = new QEvent(QEvent::None); - enabledTransitions = selectTransitions(e); + enabledTransitions = selectTransitions(e, &calculationCache); if (enabledTransitions.isEmpty()) { delete e; e = 0; } - if (enabledTransitions.isEmpty() && ((e = dequeueInternalEvent()) != 0)) { + while (enabledTransitions.isEmpty() && ((e = dequeueInternalEvent()) != 0)) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": dequeued internal event" << e << "of type" << e->type(); #endif - enabledTransitions = selectTransitions(e); + enabledTransitions = selectTransitions(e, &calculationCache); if (enabledTransitions.isEmpty()) { delete e; e = 0; } } - if (enabledTransitions.isEmpty()) { - if ((e = dequeueExternalEvent()) != 0) { + while (enabledTransitions.isEmpty() && ((e = dequeueExternalEvent()) != 0)) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": dequeued external event" << e << "of type" << e->type(); #endif - enabledTransitions = selectTransitions(e); + enabledTransitions = selectTransitions(e, &calculationCache); if (enabledTransitions.isEmpty()) { delete e; e = 0; } - } else { - if (isInternalEventQueueEmpty()) { - processing = false; - stopProcessingReason = EventQueueEmpty; - } - } } - if (!enabledTransitions.isEmpty()) { - didChange = true; - q->beginMicrostep(e); - microstep(e, enabledTransitions); - q->endMicrostep(e); - } - else { + if (enabledTransitions.isEmpty()) { + processing = false; + stopProcessingReason = EventQueueEmpty; noMicrostep(); #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": no transitions enabled"; #endif + } else { + didChange = true; + q->beginMicrostep(e); + microstep(e, enabledTransitions, &calculationCache); + q->endMicrostep(e); } delete e; } @@ -1976,12 +2144,17 @@ void QStateMachinePrivate::emitStateFinished(QState *forState, QFinalState *guil Q_ASSERT(guiltyState); #ifdef QSTATEMACHINE_DEBUG + Q_Q(QStateMachine); qDebug() << q << ": emitting finished signal for" << forState; #endif QStatePrivate::get(forState)->emitFinished(); } +void QStateMachinePrivate::startupHook() +{ +} + namespace _QStateMachine_Internal{ class GoToStateTransition : public QAbstractTransition @@ -2554,14 +2727,18 @@ void QStateMachine::setRunning(bool running) event queue. Events are processed in the order posted. The state machine takes ownership of the event and deletes it once it has been processed. - You can only post events when the state machine is running. + You can only post events when the state machine is running or when it is starting up. \sa postDelayedEvent() */ void QStateMachine::postEvent(QEvent *event, EventPriority priority) { Q_D(QStateMachine); - if (d->state != QStateMachinePrivate::Running) { + switch (d->state) { + case QStateMachinePrivate::Running: + case QStateMachinePrivate::Starting: + break; + default: qWarning("QStateMachine::postEvent: cannot post event when the state machine is not running"); return; } diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index a66232ee88..426f2732df 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -75,6 +75,7 @@ class QState; class QAbstractAnimation; #endif +struct CalculationCache; class QStateMachine; class Q_CORE_EXPORT QStateMachinePrivate : public QStatePrivate { @@ -124,17 +125,18 @@ public: void clearHistory(); QAbstractTransition *createInitialTransition() const; - void removeConflictingTransitions(QList &enabledTransitions); - void microstep(QEvent *event, const QList &transitionList); + void removeConflictingTransitions(QList &enabledTransitions, CalculationCache *cache); + void microstep(QEvent *event, const QList &transitionList, CalculationCache *cache); + QList selectTransitions(QEvent *event, CalculationCache *cache); virtual void noMicrostep(); virtual void processedPendingEvents(bool didChange); virtual void beginMacrostep(); virtual void endMacrostep(bool didChange); - QList selectTransitions(QEvent *event); void exitStates(QEvent *event, const QList &statesToExit_sorted, const QHash > &assignmentsForEnteredStates); - QList computeExitSet(const QList &enabledTransitions); - QSet computeExitSet_Unordered(const QList &enabledTransitions); + QList computeExitSet(const QList &enabledTransitions, CalculationCache *cache); + QSet computeExitSet_Unordered(const QList &enabledTransitions, CalculationCache *cache); + QSet computeExitSet_Unordered(QAbstractTransition *t, CalculationCache *cache); void executeTransitionContent(QEvent *event, const QList &transitionList); void enterStates(QEvent *event, const QList &exitedStates_sorted, const QList &statesToEnter_sorted, @@ -145,9 +147,10 @@ public: #endif ); QList computeEntrySet(const QList &enabledTransitions, - QSet &statesForDefaultEntry); + QSet &statesForDefaultEntry, CalculationCache *cache); QAbstractState *getTransitionDomain(QAbstractTransition *t, - const QList &effectiveTargetStates) const; + const QList &effectiveTargetStates, + CalculationCache *cache) const; void addDescendantStatesToEnter(QAbstractState *state, QSet &statesToEnter, QSet &statesForDefaultEntry); @@ -199,6 +202,7 @@ public: void cancelAllDelayedEvents(); virtual void emitStateFinished(QState *forState, QFinalState *guiltyState); + virtual void startupHook(); #ifndef QT_NO_PROPERTIES class RestorableId { @@ -206,7 +210,8 @@ public: QObject *obj; QByteArray prop; // two overloads because friends can't have default arguments - friend uint qHash(const RestorableId &key, uint seed) Q_DECL_NOEXCEPT_EXPR(noexcept(std::declval())) + friend uint qHash(const RestorableId &key, uint seed) + Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(std::declval()))) { return qHash(qMakePair(key.obj, key.prop), seed); } friend uint qHash(const RestorableId &key) Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(key, 0U))) { return qHash(key, 0U); } diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index b8544b1f0a..2008f76621 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -57,6 +57,16 @@ #include +#ifdef Q_OS_WINRT +namespace ABI { + namespace Windows { + namespace Foundation { + struct IAsyncAction; + } + } +} +#endif // Q_OS_WINRT + QT_BEGIN_NAMESPACE class QAbstractEventDispatcher; @@ -125,10 +135,6 @@ private: #ifndef QT_NO_THREAD -#ifdef Q_OS_WINRT -namespace ABI { namespace Windows { namespace Foundation { struct IAsyncAction; } } } -#endif - class QThreadPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QThread) diff --git a/src/corelib/tools/qcollator.cpp b/src/corelib/tools/qcollator.cpp index 9148ecf6fc..615b7a4e3e 100644 --- a/src/corelib/tools/qcollator.cpp +++ b/src/corelib/tools/qcollator.cpp @@ -87,7 +87,7 @@ QCollator::QCollator(const QCollator &other) } /*! - Destroys the collator. + Destructor for QCollator. */ QCollator::~QCollator() { @@ -109,8 +109,8 @@ QCollator &QCollator::operator=(const QCollator &other) return *this; } -/* - \fn void QCollator::QCollator(QCollator &&other) +/*! + \fn QCollator::QCollator(QCollator &&other) Move constructor. Moves from \a other into this collator. @@ -119,8 +119,8 @@ QCollator &QCollator::operator=(const QCollator &other) one of the assignment operators is undefined. */ -/* - \fn QCollator &QCollator::operator=(QCollator &&other) +/*! + \fn QCollator & QCollator::operator=(QCollator && other) Move-assigns from \a other to this collator. @@ -366,6 +366,12 @@ QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other) return *this; } +/*! + \fn QCollatorSortKey &QCollatorSortKey::operator=(QCollatorSortKey && other) + + Move-assigns \a other to this collator key. +*/ + /*! \fn bool operator<(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs) \relates QCollatorSortKey @@ -376,6 +382,12 @@ QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other) \sa QCollatorSortKey::compare() */ +/*! + \fn void QCollatorSortKey::swap(QCollatorSortKey & other) + + Swaps this collator key with \a other. +*/ + /*! \fn int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const diff --git a/src/corelib/tools/qcommandlineparser.cpp b/src/corelib/tools/qcommandlineparser.cpp index 7e49253f9b..4cc3a2c293 100644 --- a/src/corelib/tools/qcommandlineparser.cpp +++ b/src/corelib/tools/qcommandlineparser.cpp @@ -119,8 +119,8 @@ public: QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const { - const NameHash_t::const_iterator it = nameHash.find(optionName); - if (it == nameHash.end()) { + const NameHash_t::const_iterator it = nameHash.constFind(optionName); + if (it == nameHash.cend()) { qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName)); return QStringList(); } @@ -847,8 +847,8 @@ QString QCommandLineParser::value(const QString &optionName) const QStringList QCommandLineParser::values(const QString &optionName) const { d->checkParsed("values"); - const NameHash_t::const_iterator it = d->nameHash.find(optionName); - if (it != d->nameHash.end()) { + const NameHash_t::const_iterator it = d->nameHash.constFind(optionName); + if (it != d->nameHash.cend()) { const int optionOffset = *it; QStringList values = d->optionValuesHash.value(optionOffset); if (values.isEmpty()) diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index fc4fb1e7cb..41d198f9bc 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -291,7 +291,7 @@ QContiguousCache &QContiguousCache::operator=(const QContiguousCache &o { other.d->ref.ref(); if (!d->ref.deref()) - freeData(d); + freeData(p); d = other.d; if (!d->sharable) detach_helper(); diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index 255e9557e2..eaa695ef27 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -1362,11 +1362,11 @@ int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex \internal returns - 0 if str == QDateTimeEdit::tr("AM") - 1 if str == QDateTimeEdit::tr("PM") - 2 if str can become QDateTimeEdit::tr("AM") - 3 if str can become QDateTimeEdit::tr("PM") - 4 if str can become QDateTimeEdit::tr("PM") and can become QDateTimeEdit::tr("AM") + 0 if str == tr("AM") + 1 if str == tr("PM") + 2 if str can become tr("AM") + 3 if str can become tr("PM") + 4 if str can become tr("PM") and can become tr("AM") -1 can't become anything sensible */ @@ -1737,9 +1737,9 @@ QDateTime QDateTimeParser::getMaximum() const QString QDateTimeParser::getAmPmText(AmPm ap, Case cs) const { if (ap == AmText) { - return (cs == UpperCase ? QLatin1String("AM") : QLatin1String("am")); + return (cs == UpperCase ? tr("AM") : tr("am")); } else { - return (cs == UpperCase ? QLatin1String("PM") : QLatin1String("pm")); + return (cs == UpperCase ? tr("PM") : tr("pm")); } } diff --git a/src/corelib/tools/qdatetimeparser_p.h b/src/corelib/tools/qdatetimeparser_p.h index 55dc3bf7a0..9457e35ad5 100644 --- a/src/corelib/tools/qdatetimeparser_p.h +++ b/src/corelib/tools/qdatetimeparser_p.h @@ -54,7 +54,7 @@ # include "QtCore/qvariant.h" #endif #include "QtCore/qvector.h" - +#include "QtCore/qcoreapplication.h" #define QDATETIMEEDIT_TIME_MIN QTime(0, 0, 0, 0) #define QDATETIMEEDIT_TIME_MAX QTime(23, 59, 59, 999) @@ -72,6 +72,7 @@ QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QDateTimeParser { + Q_DECLARE_TR_FUNCTIONS(QDateTimeParser) public: enum Context { FromString, diff --git a/src/corelib/tools/qpair.qdoc b/src/corelib/tools/qpair.qdoc index 48555ed6d1..4452d2f0b8 100644 --- a/src/corelib/tools/qpair.qdoc +++ b/src/corelib/tools/qpair.qdoc @@ -96,6 +96,30 @@ \sa qMakePair() */ +\fn void QPair::swap(QPair &other) + + \since 5.5 + Swaps this pair with \a other. + + Equivalent to + \code + qSwap(this->first, other.first); + qSwap(this->second, other.second); + \endcode + + Swap overloads are found in namespace \c std as well as via + argument-dependent lookup (ADL) in \c{T}'s namespace. +*/ + +/*! +\fn void swap(QPair &lhs, QPair &rhs) + \overload + \relates QPair + \since 5.5 + + Swaps \a lhs with \a rhs. +*/ + /*! \fn QPair::QPair(const QPair &p) \since 5.2 @@ -108,37 +132,27 @@ */ /*! - \fn QPair &QPair::operator=(const QPair &p) + \fn QPair::QPair(QPair &&p) \since 5.2 - Copies the pair \a p onto this pair. + Move-constructs a QPair instance, making it point to the same object that + \a p was pointing to. +*/ + +/*! + \fn QPair & QPair::operator=(const QPair &p) + \since 5.2 + + Copies pair \a p into this pair. \sa qMakePair() */ /*! - \fn void QPair::swap(QPair &other) - \since 5.5 + \fn QPair & QPair::operator=(QPair &&p) + \since 5.2 - Swaps this pair with \a other. - - Equivalent to - \code - qSwap(this->first, other.first); - qSwap(this->second, other.second); - \endcode - - Swap overloads are found in namespace \c std as well as via - argument-dependent lookup (ADL) in \c{T}'s namespace. -*/ - -/*! - \fn void swap(QPair &lhs, QPair &rhs) - \overload - \relates QPair - \since 5.5 - - Swaps \a lhs with \a rhs. + Move-assigns pair \a p into this pair instance. */ /*! \fn bool operator==(const QPair &p1, const QPair &p2) diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp index 18dd2d12c2..47cad6349c 100644 --- a/src/corelib/tools/qregularexpression.cpp +++ b/src/corelib/tools/qregularexpression.cpp @@ -1829,6 +1829,13 @@ bool QRegularExpression::operator==(const QRegularExpression &re) const (d->pattern == re.d->pattern && d->patternOptions == re.d->patternOptions); } +/*! + \fn QRegularExpression & QRegularExpression::operator=(QRegularExpression && re) + + Move-assigns the regular expression \a re to this object, and returns a reference + to the copy. Both the pattern and the pattern options are copied. +*/ + /*! \fn bool QRegularExpression::operator!=(const QRegularExpression &re) const @@ -1955,6 +1962,13 @@ QRegularExpressionMatch &QRegularExpressionMatch::operator=(const QRegularExpres return *this; } +/*! + \fn QRegularExpressionMatch &QRegularExpressionMatch::operator=(QRegularExpressionMatch &&match) + + Move-assigns the match result \a match to this object, and returns a reference + to the copy. +*/ + /*! \fn void QRegularExpressionMatch::swap(QRegularExpressionMatch &other) @@ -2319,6 +2333,12 @@ QRegularExpressionMatchIterator &QRegularExpressionMatchIterator::operator=(cons return *this; } +/*! + \fn QRegularExpressionMatchIterator &QRegularExpressionMatchIterator::operator=(QRegularExpressionMatchIterator &&iterator) + + Move-assigns the \a iterator to this object. +*/ + /*! \fn void QRegularExpressionMatchIterator::swap(QRegularExpressionMatchIterator &other) diff --git a/src/corelib/tools/qscopedpointer.cpp b/src/corelib/tools/qscopedpointer.cpp index 35551f4061..c113c38aa2 100644 --- a/src/corelib/tools/qscopedpointer.cpp +++ b/src/corelib/tools/qscopedpointer.cpp @@ -254,6 +254,13 @@ QT_BEGIN_NAMESPACE Constructs a QScopedArrayPointer instance. */ +/*! + \fn QScopedArrayPointer::QScopedArrayPointer(D * p, QtPrivate::QScopedArrayEnsureSameType::Type = 0) + \internal + + Constructs a QScopedArrayPointer and stores the array of objects. +*/ + /*! \fn T *QScopedArrayPointer::operator[](int i) diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc index c4f33deed6..495329b90d 100644 --- a/src/corelib/tools/qset.qdoc +++ b/src/corelib/tools/qset.qdoc @@ -126,6 +126,13 @@ \sa operator=() */ +/*! + \fn QSet::QSet(QSet && other) + + Move-constructs a QSet instance, making it point to the same object that \a other was pointing to. +*/ + + /*! \fn QSet &QSet::operator=(const QSet &other) @@ -133,6 +140,12 @@ this set. */ +/*! + \fn QSet &QSet::operator=(QSet &&other) + + Move-assigns the \a other set to this set. +*/ + /*! \fn void QSet::swap(QSet &other) diff --git a/src/corelib/tools/qsize.h b/src/corelib/tools/qsize.h index 6e7ed40dff..e71eeb607e 100644 --- a/src/corelib/tools/qsize.h +++ b/src/corelib/tools/qsize.h @@ -54,15 +54,15 @@ public: Q_DECL_RELAXED_CONSTEXPR inline void setWidth(int w) Q_DECL_NOTHROW; Q_DECL_RELAXED_CONSTEXPR inline void setHeight(int h) Q_DECL_NOTHROW; void transpose() Q_DECL_NOTHROW; - Q_DECL_CONSTEXPR inline QSize transposed() const Q_DECL_NOTHROW; + Q_DECL_CONSTEXPR inline QSize transposed() const Q_DECL_NOTHROW Q_REQUIRED_RESULT; inline void scale(int w, int h, Qt::AspectRatioMode mode) Q_DECL_NOTHROW; inline void scale(const QSize &s, Qt::AspectRatioMode mode) Q_DECL_NOTHROW; - QSize scaled(int w, int h, Qt::AspectRatioMode mode) const Q_DECL_NOTHROW; - QSize scaled(const QSize &s, Qt::AspectRatioMode mode) const Q_DECL_NOTHROW; + QSize scaled(int w, int h, Qt::AspectRatioMode mode) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + QSize scaled(const QSize &s, Qt::AspectRatioMode mode) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; - Q_DECL_CONSTEXPR inline QSize expandedTo(const QSize &) const Q_DECL_NOTHROW; - Q_DECL_CONSTEXPR inline QSize boundedTo(const QSize &) const Q_DECL_NOTHROW; + Q_DECL_CONSTEXPR inline QSize expandedTo(const QSize &) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + Q_DECL_CONSTEXPR inline QSize boundedTo(const QSize &) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; Q_DECL_RELAXED_CONSTEXPR inline int &rwidth() Q_DECL_NOTHROW; Q_DECL_RELAXED_CONSTEXPR inline int &rheight() Q_DECL_NOTHROW; @@ -214,15 +214,15 @@ public: Q_DECL_RELAXED_CONSTEXPR inline void setWidth(qreal w) Q_DECL_NOTHROW; Q_DECL_RELAXED_CONSTEXPR inline void setHeight(qreal h) Q_DECL_NOTHROW; void transpose() Q_DECL_NOTHROW; - Q_DECL_CONSTEXPR inline QSizeF transposed() const Q_DECL_NOTHROW; + Q_DECL_CONSTEXPR inline QSizeF transposed() const Q_DECL_NOTHROW Q_REQUIRED_RESULT; inline void scale(qreal w, qreal h, Qt::AspectRatioMode mode) Q_DECL_NOTHROW; inline void scale(const QSizeF &s, Qt::AspectRatioMode mode) Q_DECL_NOTHROW; - QSizeF scaled(qreal w, qreal h, Qt::AspectRatioMode mode) const Q_DECL_NOTHROW; - QSizeF scaled(const QSizeF &s, Qt::AspectRatioMode mode) const Q_DECL_NOTHROW; + QSizeF scaled(qreal w, qreal h, Qt::AspectRatioMode mode) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + QSizeF scaled(const QSizeF &s, Qt::AspectRatioMode mode) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; - Q_DECL_CONSTEXPR inline QSizeF expandedTo(const QSizeF &) const Q_DECL_NOTHROW; - Q_DECL_CONSTEXPR inline QSizeF boundedTo(const QSizeF &) const Q_DECL_NOTHROW; + Q_DECL_CONSTEXPR inline QSizeF expandedTo(const QSizeF &) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; + Q_DECL_CONSTEXPR inline QSizeF boundedTo(const QSizeF &) const Q_DECL_NOTHROW Q_REQUIRED_RESULT; Q_DECL_RELAXED_CONSTEXPR inline qreal &rwidth() Q_DECL_NOTHROW; Q_DECL_RELAXED_CONSTEXPR inline qreal &rheight() Q_DECL_NOTHROW; diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 373d25c6ad..2585686156 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -2721,6 +2721,8 @@ bool QString::operator<(QLatin1String other) const /*! \fn bool QString::operator<=(const QString &s1, const QString &s2) + \relates Qstring + Returns \c true if string \a s1 is lexically less than or equal to string \a s2; otherwise returns \c false. @@ -2766,9 +2768,10 @@ bool QString::operator<(QLatin1String other) const */ /*! \fn bool QString::operator>(const QString &s1, const QString &s2) + \relates QString - Returns \c true if string \a s1 is lexically greater than string \a - s2; otherwise returns \c false. + Returns \c true if string \a s1 is lexically greater than string \a s2; + otherwise returns \c false. The comparison is based exclusively on the numeric Unicode values of the characters and is very fast, but is not what a human would @@ -8922,6 +8925,110 @@ bool operator<(const QStringRef &s1,const QStringRef &s2) this string reference, returning the result. */ +/*! + \fn bool QStringRef::operator==(const char * s) const + + \overload operator==() + + The \a s byte array is converted to a QStringRef using the + fromUtf8() function. This function stops conversion at the + first NUL character found, or the end of the byte array. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. This + can be useful if you want to ensure that all user-visible strings + go through QObject::tr(), for example. + + Returns \c true if this string is lexically equal to the parameter + string \a s. Otherwise returns \c false. + +*/ + +/*! + \fn bool QStringRef::operator!=(const char * s) const + + \overload operator!=() + + The \a s const char pointer is converted to a QStringRef using + the fromUtf8() function. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. This + can be useful if you want to ensure that all user-visible strings + go through QObject::tr(), for example. + + Returns \c true if this string is not lexically equal to the parameter + string \a s. Otherwise returns \c false. +*/ + +/*! + \fn bool QStringRef::operator<(const char * s) const + + \overload operator<() + + The \a s const char pointer is converted to a QStringRef using + the fromUtf8() function. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. This + can be useful if you want to ensure that all user-visible strings + go through QObject::tr(), for example. + + Returns \c true if this string is lexically smaller than the parameter + string \a s. Otherwise returns \c false. +*/ + +/*! + \fn bool QStringRef::operator<=(const char * s) const + + \overload operator<=() + + The \a s const char pointer is converted to a QStringRef using + the fromUtf8() function. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. This + can be useful if you want to ensure that all user-visible strings + go through QObject::tr(), for example. + + Returns \c true if this string is lexically smaller than or equal to the parameter + string \a s. Otherwise returns \c false. +*/ + +/*! + \fn bool QStringRef::operator>(const char * s) const + + + \overload operator>() + + The \a s const char pointer is converted to a QStringRef using + the fromUtf8() function. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. This + can be useful if you want to ensure that all user-visible strings + go through QObject::tr(), for example. + + Returns \c true if this string is lexically greater than the parameter + string \a s. Otherwise returns \c false. +*/ + +/*! + \fn bool QStringRef::operator>= (const char * s) const + + \overload operator>=() + + The \a s const char pointer is converted to a QStringRef using + the fromUtf8() function. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. This + can be useful if you want to ensure that all user-visible strings + go through QObject::tr(), for example. + + Returns \c true if this string is lexically greater than or equal to the + parameter string \a s. Otherwise returns \c false. +*/ /*! \typedef QString::Data \internal @@ -10332,7 +10439,6 @@ QString QString::toHtmlEscaped() const \endlist */ - /*! \internal */ diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 532b294c28..670d94279d 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -498,7 +498,7 @@ public: }; QString normalized(NormalizationForm mode, QChar::UnicodeVersion version = QChar::Unicode_Unassigned) const Q_REQUIRED_RESULT; - QString repeated(int times) const; + QString repeated(int times) const Q_REQUIRED_RESULT; const ushort *utf16() const; diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index cec8ad62cb..32b76ee5bd 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -183,9 +183,6 @@ DEFINEFUNC(dbus_bool_t , dbus_connection_add_filter, (DBusConnection void *user_data, DBusFreeFunction free_data_function), (connection, function, user_data, free_data_function), return) -DEFINEFUNC(dbus_bool_t , dbus_connection_can_send_type, (DBusConnection *connection, - int type), - (connection, type), return) DEFINEFUNC(void , dbus_connection_close, (DBusConnection *connection), (connection), return) DEFINEFUNC(DBusDispatchStatus , dbus_connection_dispatch, (DBusConnection *connection), diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp index 96caa80549..77f48c03a4 100644 --- a/src/dbus/qdbusunixfiledescriptor.cpp +++ b/src/dbus/qdbusunixfiledescriptor.cpp @@ -173,6 +173,12 @@ QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileD return *this; } +/*! + \fn QDBusUnixFileDescriptor &operator=(QDBusUnixFileDescriptor &&other) + + Move-assigns \a other to this QDBusUnixFileDescriptor. +*/ + /*! Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained. */ diff --git a/src/dbus/qdbusvirtualobject.cpp b/src/dbus/qdbusvirtualobject.cpp index aeeb2a1f2b..b65e71eef7 100644 --- a/src/dbus/qdbusvirtualobject.cpp +++ b/src/dbus/qdbusvirtualobject.cpp @@ -37,11 +37,17 @@ QT_BEGIN_NAMESPACE +/*! + Constructs a QDBusVirtualObject with \a parent. +*/ QDBusVirtualObject::QDBusVirtualObject(QObject *parent) : QObject(parent) { } +/*! + Destroys the object, deleting all of its child objects. +*/ QDBusVirtualObject::~QDBusVirtualObject() { } diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index cc9d789c6a..5b6bae7cab 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -1409,6 +1409,12 @@ QAccessible::Id QAccessibleEvent::uniqueId() const Constructs a new QAccessibleStateChangeEvent for \a object. The difference to the object's previous state is in \a state. */ +/*! + \fn QAccessibleStateChangeEvent::QAccessibleStateChangeEvent(QAccessibleInterface *iface, QAccessible::State state) + Constructs a new QAccessibleStateChangeEvent. + \a iface is the interface associated with the event + \a state is the state of the accessible object. +*/ /*! \fn QAccessible::State QAccessibleStateChangeEvent::changedStates() const \brief Returns the states that have been changed. diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 6d7a40c2ef..40ba84bb14 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -606,7 +606,7 @@ QFactoryLoader *qt_iconEngineFactoryLoader() /*! Constructs a null icon. */ -QIcon::QIcon() +QIcon::QIcon() Q_DECL_NOEXCEPT : d(0) { } diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h index d87468b4f0..63e77eef99 100644 --- a/src/gui/image/qicon.h +++ b/src/gui/image/qicon.h @@ -51,22 +51,24 @@ public: enum Mode { Normal, Disabled, Active, Selected }; enum State { On, Off }; - QIcon(); + QIcon() Q_DECL_NOEXCEPT; QIcon(const QPixmap &pixmap); QIcon(const QIcon &other); #ifdef Q_COMPILER_RVALUE_REFS - QIcon(QIcon &&other) - :d(0) { qSwap(d, other.d); } + QIcon(QIcon &&other) Q_DECL_NOEXCEPT + : d(0) + { qSwap(d, other.d); } #endif explicit QIcon(const QString &fileName); // file or resource name explicit QIcon(QIconEngine *engine); ~QIcon(); QIcon &operator=(const QIcon &other); #ifdef Q_COMPILER_RVALUE_REFS - inline QIcon &operator=(QIcon &&other) + inline QIcon &operator=(QIcon &&other) Q_DECL_NOEXCEPT { qSwap(d, other.d); return *this; } #endif - inline void swap(QIcon &other) { qSwap(d, other.d); } + inline void swap(QIcon &other) Q_DECL_NOEXCEPT + { qSwap(d, other.d); } operator QVariant() const; diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 47d187fc0e..3c192a237e 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -738,7 +738,7 @@ bool QImageData::checkForAlphaPixels() const \sa isNull() */ -QImage::QImage() +QImage::QImage() Q_DECL_NOEXCEPT : QPaintDevice() { d = 0; @@ -5147,4 +5147,18 @@ QImage::Format QImage::toImageFormat(QPixelFormat format) Q_DECL_NOTHROW return Format_Invalid; } +Q_GUI_EXPORT void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient) +{ + if (orient == QImageIOHandler::TransformationNone) + return; + if (orient == QImageIOHandler::TransformationRotate270) { + src = rotated270(src); + } else { + src = qMove(src).mirrored(orient & QImageIOHandler::TransformationMirror, + orient & QImageIOHandler::TransformationFlip); + if (orient & QImageIOHandler::TransformationRotate90) + src = rotated90(src); + } +} + QT_END_NAMESPACE diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 0ccbab819f..26707021ea 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -122,7 +122,7 @@ public: #endif }; - QImage(); + QImage() Q_DECL_NOEXCEPT; QImage(const QSize &size, Format format); QImage(int width, int height, Format format); QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = 0, void *cleanupInfo = 0); @@ -137,7 +137,7 @@ public: QImage(const QImage &); #ifdef Q_COMPILER_RVALUE_REFS - inline QImage(QImage &&other) + inline QImage(QImage &&other) Q_DECL_NOEXCEPT : QPaintDevice(), d(0) { qSwap(d, other.d); } #endif @@ -145,10 +145,11 @@ public: QImage &operator=(const QImage &); #ifdef Q_COMPILER_RVALUE_REFS - inline QImage &operator=(QImage &&other) + inline QImage &operator=(QImage &&other) Q_DECL_NOEXCEPT { qSwap(d, other.d); return *this; } #endif - inline void swap(QImage &other) { qSwap(d, other.d); } + inline void swap(QImage &other) Q_DECL_NOEXCEPT + { qSwap(d, other.d); } bool isNull() const; diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp index cc9a6ae2a1..22b4bcf560 100644 --- a/src/gui/image/qimageiohandler.cpp +++ b/src/gui/image/qimageiohandler.cpp @@ -159,6 +159,43 @@ \value ProgressiveScanWrite. A handler which supports this option is expected to write the image as a progressive scan image. + + \value ImageTransformation. A handler which supports this option can read + the transformation metadata of an image. A handler that supports this option + should not apply the transformation itself. + + \value TransformedByDefault. A handler that reports support for this feature + will have image transformation metadata applied by default on read. +*/ + +/*! \enum QImageIOHandler::Transformation + \since 5.5 + + This enum describes the different transformations or orientations + supported by some image formats, usually through EXIF. + + \value TransformationNone No transformation should be applied. + + \value TransformationMirror Mirror the image horizontally. + + \value TransformationFlip Mirror the image vertically. + + \value TransformationRotate180 Rotate the image 180 degrees. + This is the same as mirroring it both horizontally and vertically. + + \value TransformationRotate90 Rotate the image 90 degrees. + + \value TransformationMirrorAndRotate90 Mirror the image horizontally + and then rotate it 90 degrees. + + \value TransformationFlipAndRotate90 Mirror the image vertically + and then rotate it 90 degrees. + + \value TransformationRotate270 Rotate the image 270 degrees. + This is the same as mirroring it both horizontally, vertically and + then rotating it 90 degrees. + + \sa QImageReader::transformation(), QImageReader::setAutoTransform(), QImageWriter::setTransformation() */ /*! diff --git a/src/gui/image/qimageiohandler.h b/src/gui/image/qimageiohandler.h index b48226f619..80cd87c4c3 100644 --- a/src/gui/image/qimageiohandler.h +++ b/src/gui/image/qimageiohandler.h @@ -86,8 +86,25 @@ public: ImageFormat, SupportedSubTypes, OptimizedWrite, - ProgressiveScanWrite + ProgressiveScanWrite, + ImageTransformation +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + , TransformedByDefault +#endif }; + + enum Transformation { + TransformationNone = 0, + TransformationMirror = 1, + TransformationFlip = 2, + TransformationRotate180 = TransformationMirror | TransformationFlip, + TransformationRotate90 = 4, + TransformationMirrorAndRotate90 = TransformationMirror | TransformationRotate90, + TransformationFlipAndRotate90 = TransformationFlip | TransformationRotate90, + TransformationRotate270 = TransformationRotate180 | TransformationRotate90 + }; + Q_DECLARE_FLAGS(Transformations, Transformation) + virtual QVariant option(ImageOption option) const; virtual void setOption(ImageOption option, const QVariant &value); virtual bool supportsOption(ImageOption option) const; diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index c2795cc38d..ba79bf40e5 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -533,6 +533,11 @@ public: int quality; QMap text; void getText(); + enum { + UsePluginDefault, + ApplyTransform, + DoNotApplyTransform + } autoTransform; // error QImageReader::ImageReaderError imageReaderError; @@ -552,6 +557,7 @@ QImageReaderPrivate::QImageReaderPrivate(QImageReader *qq) handler = 0; quality = -1; imageReaderError = QImageReader::UnknownError; + autoTransform = UsePluginDefault; q = qq; } @@ -1143,6 +1149,59 @@ QList QImageReader::supportedSubTypes() const return QList(); } +/*! + \since 5.5 + + Returns the transformation metadata of the image, including image orientation. If the format + does not support transformation metadata \c QImageIOHandler::Transformation_None is returned. + + \sa setAutoTransform(), autoTransform() +*/ +QImageIOHandler::Transformations QImageReader::transformation() const +{ + int option = QImageIOHandler::TransformationNone; + if (d->initHandler() && d->handler->supportsOption(QImageIOHandler::ImageTransformation)) + option = d->handler->option(QImageIOHandler::ImageTransformation).toInt(); + return QImageIOHandler::Transformations(option); +} + +/*! + \since 5.5 + + Sets if images returned by read() should have transformation metadata automatically applied. + + \sa autoTransform(), transform(), read() +*/ +void QImageReader::setAutoTransform(bool enabled) +{ + d->autoTransform = enabled ? QImageReaderPrivate::ApplyTransform + : QImageReaderPrivate::DoNotApplyTransform; +} + +/*! + \since 5.5 + + Returns \c true if the image handler will apply transformation metadata on read(). + + \sa setAutoTransform(), transformation(), read() +*/ +bool QImageReader::autoTransform() const +{ + switch (d->autoTransform) { + case QImageReaderPrivate::ApplyTransform: + return true; + case QImageReaderPrivate::DoNotApplyTransform: + return false; + case QImageReaderPrivate::UsePluginDefault: + if (d->initHandler()) + return d->handler->supportsOption(QImageIOHandler::TransformedByDefault); + // no break + default: + break; + } + return false; +} + /*! Returns \c true if an image can be read for the device (i.e., the image format is supported, and the device seems to contain valid @@ -1185,6 +1244,8 @@ QImage QImageReader::read() return read(&image) ? image : QImage(); } +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); + /*! \overload @@ -1294,6 +1355,8 @@ bool QImageReader::read(QImage *image) if (!disable2xImageLoading && QFileInfo(fileName()).baseName().endsWith(QLatin1String("@2x"))) { image->setDevicePixelRatio(2.0); } + if (autoTransform()) + qt_imageTransform(*image, transformation()); return true; } diff --git a/src/gui/image/qimagereader.h b/src/gui/image/qimagereader.h index 34191ed657..27a29bed49 100644 --- a/src/gui/image/qimagereader.h +++ b/src/gui/image/qimagereader.h @@ -105,6 +105,11 @@ public: bool supportsAnimation() const; + QImageIOHandler::Transformations transformation() const; + + void setAutoTransform(bool enabled); + bool autoTransform() const; + QByteArray subType() const; QList supportedSubTypes() const; diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index b418101163..e9de1db4b2 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -254,6 +255,7 @@ public: QByteArray subType; bool optimizedWrite; bool progressiveScanWrite; + QImageIOHandler::Transformations transformation; // error QImageWriter::ImageWriterError imageWriterError; @@ -277,6 +279,7 @@ QImageWriterPrivate::QImageWriterPrivate(QImageWriter *qq) progressiveScanWrite = false; imageWriterError = QImageWriter::UnknownError; errorString = QImageWriter::tr("Unknown error"); + transformation = QImageIOHandler::TransformationNone; q = qq; } @@ -615,6 +618,33 @@ bool QImageWriter::progressiveScanWrite() const return d->progressiveScanWrite; } +/*! + \since 5.5 + + Sets the image transformations metadata including orientation. + + If transformation metadata is not supported by the image format, + the transform is applied before writing. + + \sa transformation(), write() +*/ +void QImageWriter::setTransformation(QImageIOHandler::Transformations transform) +{ + d->transformation = transform; +} + +/*! + \since 5.5 + + Returns the transformation and orientation the image has been set to written with. + + \sa setTransformation() +*/ +QImageIOHandler::Transformations QImageWriter::transformation() const +{ + return d->transformation; +} + /*! \obsolete @@ -694,6 +724,8 @@ bool QImageWriter::canWrite() const return d->canWriteHelper(); } +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); + /*! Writes the image \a image to the assigned device or file name. Returns \c true on success; otherwise returns \c false. If the @@ -708,6 +740,7 @@ bool QImageWriter::write(const QImage &image) if (!canWrite()) return false; + QImage img = image; if (d->handler->supportsOption(QImageIOHandler::Quality)) d->handler->setOption(QImageIOHandler::Quality, d->quality); if (d->handler->supportsOption(QImageIOHandler::CompressionRatio)) @@ -722,8 +755,12 @@ bool QImageWriter::write(const QImage &image) d->handler->setOption(QImageIOHandler::OptimizedWrite, d->optimizedWrite); if (d->handler->supportsOption(QImageIOHandler::ProgressiveScanWrite)) d->handler->setOption(QImageIOHandler::ProgressiveScanWrite, d->progressiveScanWrite); + if (d->handler->supportsOption(QImageIOHandler::ImageTransformation)) + d->handler->setOption(QImageIOHandler::ImageTransformation, int(d->transformation)); + else + qt_imageTransform(img, d->transformation); - if (!d->handler->write(image)) + if (!d->handler->write(img)) return false; if (QFile *file = qobject_cast(d->device)) file->flush(); diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h index 96d8f51b3a..7f92595c53 100644 --- a/src/gui/image/qimagewriter.h +++ b/src/gui/image/qimagewriter.h @@ -89,6 +89,9 @@ public: void setProgressiveScanWrite(bool progressive); bool progressiveScanWrite() const; + QImageIOHandler::Transformations transformation() const; + void setTransformation(QImageIOHandler::Transformations orientation); + // Obsolete as of 4.1 void setDescription(const QString &description); QString description() const; diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 839f90f17c..4ff3917fe6 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -714,7 +714,7 @@ public: }; QJpegHandlerPrivate(QJpegHandler *qq) - : quality(75), exifOrientation(1), iod_src(0), + : quality(75), transformation(QImageIOHandler::TransformationNone), iod_src(0), rgb888ToRgb32ConverterPtr(qt_convert_rgb888_to_rgb32), state(Ready), optimize(false), progressive(false), q(qq) {} @@ -730,10 +730,9 @@ public: bool readJpegHeader(QIODevice*); bool read(QImage *image); - void applyExifOrientation(QImage *image); int quality; - int exifOrientation; + QImageIOHandler::Transformations transformation; QVariant size; QImage::Format format; QSize scaledSize; @@ -761,9 +760,8 @@ static bool readExifHeader(QDataStream &stream) char prefix[6]; if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix)) return false; - if (prefix[0] != 'E' || prefix[1] != 'x' || prefix[2] != 'i' || prefix[3] != 'f' || prefix[4] != 0 || prefix[5] != 0) - return false; - return true; + static const char exifMagic[6] = {'E', 'x', 'i', 'f', 0, 0}; + return memcmp(prefix, exifMagic, 6) == 0; } /* @@ -787,6 +785,7 @@ static int getExifOrientation(QByteArray &exifData) quint16 val; quint32 offset; + const qint64 headerStart = stream.device()->pos(); // read byte order marker stream >> val; @@ -803,20 +802,20 @@ static int getExifOrientation(QByteArray &exifData) return -1; stream >> offset; - // we have already used 8 bytes of TIFF header - offset -= 8; // read IFD while (!stream.atEnd()) { quint16 numEntries; // skip offset bytes to get the next IFD - if (stream.skipRawData(offset) != (qint32)offset) + const qint64 bytesToSkip = offset - (stream.device()->pos() - headerStart); + + if (stream.skipRawData(bytesToSkip) != bytesToSkip) return -1; stream >> numEntries; - for (;numEntries > 0; --numEntries) { + for (; numEntries > 0; --numEntries) { quint16 tag; quint16 type; quint32 components; @@ -825,7 +824,7 @@ static int getExifOrientation(QByteArray &exifData) stream >> tag >> type >> components >> value >> dummy; if (tag == 0x0112) { // Tag Exif.Image.Orientation - if (components !=1) + if (components != 1) return -1; if (type != 3) // we are expecting it to be an unsigned short return -1; @@ -847,6 +846,31 @@ static int getExifOrientation(QByteArray &exifData) // No Exif orientation was found return 0; } + +static QImageIOHandler::Transformations exif2Qt(int exifOrientation) +{ + switch (exifOrientation) { + case 1: // normal + return QImageIOHandler::TransformationNone; + case 2: // mirror horizontal + return QImageIOHandler::TransformationMirror; + case 3: // rotate 180 + return QImageIOHandler::TransformationRotate180; + case 4: // mirror vertical + return QImageIOHandler::TransformationFlip; + case 5: // mirror horizontal and rotate 270 CW + return QImageIOHandler::TransformationFlipAndRotate90; + case 6: // rotate 90 CW + return QImageIOHandler::TransformationRotate90; + case 7: // mirror horizontal and rotate 90 CW + return QImageIOHandler::TransformationMirrorAndRotate90; + case 8: // rotate 270 CW + return QImageIOHandler::TransformationRotate270; + } + qWarning("Invalid EXIF orientation"); + return QImageIOHandler::TransformationNone; +} + /*! \internal */ @@ -866,7 +890,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) if (!setjmp(err.setjmp_buffer)) { jpeg_save_markers(&info, JPEG_COM, 0xFFFF); - jpeg_save_markers(&info, JPEG_APP0+1, 0xFFFF); // Exif uses APP1 marker + jpeg_save_markers(&info, JPEG_APP0 + 1, 0xFFFF); // Exif uses APP1 marker (void) jpeg_read_header(&info, TRUE); @@ -897,16 +921,18 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) description += key + QLatin1String(": ") + value.simplified(); readTexts.append(key); readTexts.append(value); - } else if (marker->marker == JPEG_APP0+1) { + } else if (marker->marker == JPEG_APP0 + 1) { exifData.append((const char*)marker->data, marker->data_length); } } - if (exifData.size()) { + if (!exifData.isEmpty()) { // Exif data present - int orientation = getExifOrientation(exifData); - if (orientation > 0) - exifOrientation = orientation; + int exifOrientation = getExifOrientation(exifData); + if (exifOrientation == -1) + return false; + if (exifOrientation > 0) + transformation = exif2Qt(exifOrientation); } state = ReadHeader; @@ -922,48 +948,6 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) return true; } -void QJpegHandlerPrivate::applyExifOrientation(QImage *image) -{ - // This is not an optimized implementation, but easiest to maintain - QTransform transform; - - switch (exifOrientation) { - case 1: // normal - break; - case 2: // mirror horizontal - *image = image->mirrored(true, false); - break; - case 3: // rotate 180 - transform.rotate(180); - *image = image->transformed(transform); - break; - case 4: // mirror vertical - *image = image->mirrored(false, true); - break; - case 5: // mirror horizontal and rotate 270 CCW - *image = image->mirrored(true, false); - transform.rotate(270); - *image = image->transformed(transform); - break; - case 6: // rotate 90 CW - transform.rotate(90); - *image = image->transformed(transform); - break; - case 7: // mirror horizontal and rotate 90 CW - *image = image->mirrored(true, false); - transform.rotate(90); - *image = image->transformed(transform); - break; - case 8: // rotate 270 CW - transform.rotate(-90); - *image = image->transformed(transform); - break; - default: - qWarning("This should never happen"); - } - exifOrientation = 1; -} - bool QJpegHandlerPrivate::read(QImage *image) { if(state == Ready) @@ -975,7 +959,6 @@ bool QJpegHandlerPrivate::read(QImage *image) if (success) { for (int i = 0; i < readTexts.size()-1; i+=2) image->setText(readTexts.at(i), readTexts.at(i+1)); - applyExifOrientation(image); state = Ready; return true; @@ -1053,8 +1036,16 @@ bool QJpegHandler::read(QImage *image) return d->read(image); } +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); + bool QJpegHandler::write(const QImage &image) { + if (d->transformation != QImageIOHandler::TransformationNone) { + // We don't support writing EXIF headers so apply the transform to the data. + QImage img = image; + qt_imageTransform(img, d->transformation); + return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive); + } return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive); } @@ -1068,7 +1059,8 @@ bool QJpegHandler::supportsOption(ImageOption option) const || option == Size || option == ImageFormat || option == OptimizedWrite - || option == ProgressiveScanWrite; + || option == ProgressiveScanWrite + || option == ImageTransformation; } QVariant QJpegHandler::option(ImageOption option) const @@ -1095,6 +1087,9 @@ QVariant QJpegHandler::option(ImageOption option) const return d->optimize; case ProgressiveScanWrite: return d->progressive; + case ImageTransformation: + d->readJpegHeader(device()); + return int(d->transformation); default: break; } @@ -1126,6 +1121,11 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value) case ProgressiveScanWrite: d->progressive = value.toBool(); break; + case ImageTransformation: { + int transformation = value.toInt(); + if (transformation > 0 && transformation < 8) + d->transformation = QImageIOHandler::Transformations(transformation); + } default: break; } diff --git a/src/gui/image/qpicture.h b/src/gui/image/qpicture.h index 9bb193321b..c3897a1935 100644 --- a/src/gui/image/qpicture.h +++ b/src/gui/image/qpicture.h @@ -72,10 +72,11 @@ public: QPicture& operator=(const QPicture &p); #ifdef Q_COMPILER_RVALUE_REFS - inline QPicture &operator=(QPicture &&other) + inline QPicture &operator=(QPicture &&other) Q_DECL_NOEXCEPT { qSwap(d_ptr, other.d_ptr); return *this; } #endif - inline void swap(QPicture &other) { d_ptr.swap(other.d_ptr); } + inline void swap(QPicture &other) Q_DECL_NOEXCEPT + { d_ptr.swap(other.d_ptr); } void detach(); bool isDetached() const; diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 810883ea6c..51b02acfcf 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -67,10 +67,11 @@ public: QPixmap &operator=(const QPixmap &); #ifdef Q_COMPILER_RVALUE_REFS - inline QPixmap &operator=(QPixmap &&other) + inline QPixmap &operator=(QPixmap &&other) Q_DECL_NOEXCEPT { qSwap(data, other.data); return *this; } #endif - inline void swap(QPixmap &other) { qSwap(data, other.data); } + inline void swap(QPixmap &other) Q_DECL_NOEXCEPT + { qSwap(data, other.data); } operator QVariant() const; diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp index 0de47f55af..12e19440dc 100644 --- a/src/gui/image/qpixmap_win.cpp +++ b/src/gui/image/qpixmap_win.cpp @@ -40,11 +40,6 @@ #include #include -#ifdef Q_OS_WINCE -#define UNDER_NT -#include -#endif - QT_BEGIN_NAMESPACE #ifdef Q_OS_WINCE diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 3c88d2e9c1..7fbd24787e 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -676,16 +676,9 @@ QImage::Format QPngHandlerPrivate::readImageFormat() && num_palette <= 256) { // 1-bit and 8-bit color - if (bit_depth != 1) - png_set_packing(png_ptr); - png_read_update_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; } else { // 32-bit - if (bit_depth == 16) - png_set_strip_16(png_ptr); - format = QImage::Format_ARGB32; // Only add filler if no alpha, or we can get 5 channel data. if (!(color_type & PNG_COLOR_MASK_ALPHA) diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 0cf0601db9..5cca761523 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -792,8 +792,10 @@ public: explicit TouchPoint(int id = -1); TouchPoint(const TouchPoint &other); #ifdef Q_COMPILER_RVALUE_REFS - TouchPoint(TouchPoint &&other) : d(other.d) { other.d = 0; } - TouchPoint &operator=(TouchPoint &&other) + TouchPoint(TouchPoint &&other) Q_DECL_NOEXCEPT + : d(0) + { qSwap(d, other.d); } + TouchPoint &operator=(TouchPoint &&other) Q_DECL_NOEXCEPT { qSwap(d, other.d); return *this; } #endif ~TouchPoint(); @@ -801,7 +803,8 @@ public: TouchPoint &operator=(const TouchPoint &other) { if ( d != other.d ) { TouchPoint copy(other); swap(copy); } return *this; } - void swap(TouchPoint &other) { qSwap(d, other.d); } + void swap(TouchPoint &other) Q_DECL_NOEXCEPT + { qSwap(d, other.d); } int id() const; diff --git a/src/gui/kernel/qgenericpluginfactory.cpp b/src/gui/kernel/qgenericpluginfactory.cpp index 7e4727df8c..d7b9bfba06 100644 --- a/src/gui/kernel/qgenericpluginfactory.cpp +++ b/src/gui/kernel/qgenericpluginfactory.cpp @@ -69,13 +69,13 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, */ QObject *QGenericPluginFactory::create(const QString& key, const QString &specification) { +#if (!defined(Q_OS_WIN32) || defined(QT_SHARED)) && !defined(QT_NO_LIBRARY) const QString driver = key.toLower(); - -#if !defined(Q_OS_WIN32) || defined(QT_SHARED) -#ifndef QT_NO_LIBRARY if (QObject *object = qLoadPlugin1(loader(), driver, specification)) return object; -#endif +#else // (!Q_OS_WIN32 || QT_SHARED) && !QT_NO_LIBRARY + Q_UNUSED(key) + Q_UNUSED(specification) #endif return 0; } diff --git a/src/gui/kernel/qinputdevicemanager.cpp b/src/gui/kernel/qinputdevicemanager.cpp index d0dd8a4e7c..dbdb03adbb 100644 --- a/src/gui/kernel/qinputdevicemanager.cpp +++ b/src/gui/kernel/qinputdevicemanager.cpp @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE QInputDeviceManager::QInputDeviceManager(QObject *parent) : QObject(*new QInputDeviceManagerPrivate, parent) { + qRegisterMetaType(); } int QInputDeviceManager::deviceCount(DeviceType type) const diff --git a/src/gui/kernel/qinputdevicemanager_p.h b/src/gui/kernel/qinputdevicemanager_p.h index 15c84d1a82..d64793c23c 100644 --- a/src/gui/kernel/qinputdevicemanager_p.h +++ b/src/gui/kernel/qinputdevicemanager_p.h @@ -77,4 +77,6 @@ signals: QT_END_NAMESPACE +Q_DECLARE_METATYPE(QInputDeviceManager::DeviceType) + #endif // QINPUTDEVICEMANAGER_P_H diff --git a/src/gui/kernel/qopenglwindow.cpp b/src/gui/kernel/qopenglwindow.cpp index a7ba57e85e..b2025faaf1 100644 --- a/src/gui/kernel/qopenglwindow.cpp +++ b/src/gui/kernel/qopenglwindow.cpp @@ -175,129 +175,16 @@ public: this->shareContext = qt_gl_global_share_context(); } - ~QOpenGLWindowPrivate() - { - Q_Q(QOpenGLWindow); - if (q->isValid()) { - q->makeCurrent(); // this works even when the platformwindow is destroyed - paintDevice.reset(0); - fbo.reset(0); - blitter.destroy(); - q->doneCurrent(); - } - } + ~QOpenGLWindowPrivate(); static QOpenGLWindowPrivate *get(QOpenGLWindow *w) { return w->d_func(); } - void bindFBO() - { - if (updateBehavior > QOpenGLWindow::NoPartialUpdate) - fbo->bind(); - else - QOpenGLFramebufferObject::bindDefault(); - } + void bindFBO(); + void initialize(); - void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE - { - Q_UNUSED(region); - Q_Q(QOpenGLWindow); - - if (!context) { - context.reset(new QOpenGLContext); - context->setShareContext(shareContext); - context->setFormat(q->requestedFormat()); - if (!context->create()) - qWarning("QOpenGLWindow::beginPaint: Failed to create context"); - if (!context->makeCurrent(q)) - qWarning("QOpenGLWindow::beginPaint: Failed to make context current"); - - paintDevice.reset(new QOpenGLWindowPaintDevice(q)); - if (updateBehavior == QOpenGLWindow::PartialUpdateBlit) - hasFboBlit = QOpenGLFramebufferObject::hasOpenGLFramebufferBlit(); - - q->initializeGL(); - } else { - context->makeCurrent(q); - } - - const int deviceWidth = q->width() * q->devicePixelRatio(); - const int deviceHeight = q->height() * q->devicePixelRatio(); - const QSize deviceSize(deviceWidth, deviceHeight); - if (updateBehavior > QOpenGLWindow::NoPartialUpdate) { - if (!fbo || fbo->size() != deviceSize) { - QOpenGLFramebufferObjectFormat fboFormat; - fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - if (q->requestedFormat().samples() > 0) { - if (updateBehavior != QOpenGLWindow::PartialUpdateBlend) - fboFormat.setSamples(q->requestedFormat().samples()); - else - qWarning("QOpenGLWindow: PartialUpdateBlend does not support multisampling"); - } - fbo.reset(new QOpenGLFramebufferObject(deviceSize, fboFormat)); - markWindowAsDirty(); - } - } else { - markWindowAsDirty(); - } - - paintDevice->setSize(QSize(deviceWidth, deviceHeight)); - paintDevice->setDevicePixelRatio(q->devicePixelRatio()); - context->functions()->glViewport(0, 0, deviceWidth, deviceHeight); - - context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, context->defaultFramebufferObject()); - - q->paintUnderGL(); - - if (updateBehavior > QOpenGLWindow::NoPartialUpdate) - fbo->bind(); - } - - void endPaint() Q_DECL_OVERRIDE - { - Q_Q(QOpenGLWindow); - - if (updateBehavior > QOpenGLWindow::NoPartialUpdate) - fbo->release(); - - context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, context->defaultFramebufferObject()); - - if (updateBehavior == QOpenGLWindow::PartialUpdateBlit && hasFboBlit) { - const int deviceWidth = q->width() * q->devicePixelRatio(); - const int deviceHeight = q->height() * q->devicePixelRatio(); - QOpenGLExtensions extensions(context.data()); - extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle()); - extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, context->defaultFramebufferObject()); - extensions.glBlitFramebuffer(0, 0, deviceWidth, deviceHeight, - 0, 0, deviceWidth, deviceHeight, - GL_COLOR_BUFFER_BIT, GL_NEAREST); - } else if (updateBehavior > QOpenGLWindow::NoPartialUpdate) { - if (updateBehavior == QOpenGLWindow::PartialUpdateBlend) { - context->functions()->glEnable(GL_BLEND); - context->functions()->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - if (!blitter.isCreated()) - blitter.create(); - - QRect windowRect(QPoint(0, 0), fbo->size()); - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect); - blitter.bind(); - blitter.blit(fbo->texture(), target, QOpenGLTextureBlitter::OriginBottomLeft); - blitter.release(); - - if (updateBehavior == QOpenGLWindow::PartialUpdateBlend) - context->functions()->glDisable(GL_BLEND); - } - - q->paintOverGL(); - } - - void flush(const QRegion ®ion) Q_DECL_OVERRIDE - { - Q_UNUSED(region); - Q_Q(QOpenGLWindow); - context->swapBuffers(q); - emit q->frameSwapped(); - } + void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE; + void endPaint() Q_DECL_OVERRIDE; + void flush(const QRegion ®ion) Q_DECL_OVERRIDE; QOpenGLWindow::UpdateBehavior updateBehavior; bool hasFboBlit; @@ -310,6 +197,135 @@ public: QScopedPointer offscreenSurface; }; +QOpenGLWindowPrivate::~QOpenGLWindowPrivate() +{ + Q_Q(QOpenGLWindow); + if (q->isValid()) { + q->makeCurrent(); // this works even when the platformwindow is destroyed + paintDevice.reset(0); + fbo.reset(0); + blitter.destroy(); + q->doneCurrent(); + } +} + +void QOpenGLWindowPrivate::initialize() +{ + Q_Q(QOpenGLWindow); + + if (context) + return; + + context.reset(new QOpenGLContext); + context->setShareContext(shareContext); + context->setFormat(q->requestedFormat()); + if (!context->create()) + qWarning("QOpenGLWindow::beginPaint: Failed to create context"); + if (!context->makeCurrent(q)) + qWarning("QOpenGLWindow::beginPaint: Failed to make context current"); + + paintDevice.reset(new QOpenGLWindowPaintDevice(q)); + if (updateBehavior == QOpenGLWindow::PartialUpdateBlit) + hasFboBlit = QOpenGLFramebufferObject::hasOpenGLFramebufferBlit(); + + q->initializeGL(); +} + +void QOpenGLWindowPrivate::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + Q_Q(QOpenGLWindow); + + initialize(); + context->makeCurrent(q); + + const int deviceWidth = q->width() * q->devicePixelRatio(); + const int deviceHeight = q->height() * q->devicePixelRatio(); + const QSize deviceSize(deviceWidth, deviceHeight); + if (updateBehavior > QOpenGLWindow::NoPartialUpdate) { + if (!fbo || fbo->size() != deviceSize) { + QOpenGLFramebufferObjectFormat fboFormat; + fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + if (q->requestedFormat().samples() > 0) { + if (updateBehavior != QOpenGLWindow::PartialUpdateBlend) + fboFormat.setSamples(q->requestedFormat().samples()); + else + qWarning("QOpenGLWindow: PartialUpdateBlend does not support multisampling"); + } + fbo.reset(new QOpenGLFramebufferObject(deviceSize, fboFormat)); + markWindowAsDirty(); + } + } else { + markWindowAsDirty(); + } + + paintDevice->setSize(QSize(deviceWidth, deviceHeight)); + paintDevice->setDevicePixelRatio(q->devicePixelRatio()); + context->functions()->glViewport(0, 0, deviceWidth, deviceHeight); + + context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, context->defaultFramebufferObject()); + + q->paintUnderGL(); + + if (updateBehavior > QOpenGLWindow::NoPartialUpdate) + fbo->bind(); +} + +void QOpenGLWindowPrivate::endPaint() +{ + Q_Q(QOpenGLWindow); + + if (updateBehavior > QOpenGLWindow::NoPartialUpdate) + fbo->release(); + + context->functions()->glBindFramebuffer(GL_FRAMEBUFFER, context->defaultFramebufferObject()); + + if (updateBehavior == QOpenGLWindow::PartialUpdateBlit && hasFboBlit) { + const int deviceWidth = q->width() * q->devicePixelRatio(); + const int deviceHeight = q->height() * q->devicePixelRatio(); + QOpenGLExtensions extensions(context.data()); + extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo->handle()); + extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, context->defaultFramebufferObject()); + extensions.glBlitFramebuffer(0, 0, deviceWidth, deviceHeight, + 0, 0, deviceWidth, deviceHeight, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + } else if (updateBehavior > QOpenGLWindow::NoPartialUpdate) { + if (updateBehavior == QOpenGLWindow::PartialUpdateBlend) { + context->functions()->glEnable(GL_BLEND); + context->functions()->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + if (!blitter.isCreated()) + blitter.create(); + + QRect windowRect(QPoint(0, 0), fbo->size()); + QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect); + blitter.bind(); + blitter.blit(fbo->texture(), target, QOpenGLTextureBlitter::OriginBottomLeft); + blitter.release(); + + if (updateBehavior == QOpenGLWindow::PartialUpdateBlend) + context->functions()->glDisable(GL_BLEND); + } + + q->paintOverGL(); +} + +void QOpenGLWindowPrivate::bindFBO() +{ + if (updateBehavior > QOpenGLWindow::NoPartialUpdate) + fbo->bind(); + else + QOpenGLFramebufferObject::bindDefault(); +} + +void QOpenGLWindowPrivate::flush(const QRegion ®ion) +{ + Q_UNUSED(region); + Q_Q(QOpenGLWindow); + context->swapBuffers(q); + emit q->frameSwapped(); +} + void QOpenGLWindowPaintDevice::ensureActiveTarget() { QOpenGLWindowPrivate::get(m_window)->bindFBO(); @@ -631,6 +647,8 @@ void QOpenGLWindow::paintEvent(QPaintEvent *event) void QOpenGLWindow::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); + Q_D(QOpenGLWindow); + d->initialize(); resizeGL(width(), height()); } diff --git a/src/gui/kernel/qpalette.h b/src/gui/kernel/qpalette.h index e8b35aa82a..66b3f039f4 100644 --- a/src/gui/kernel/qpalette.h +++ b/src/gui/kernel/qpalette.h @@ -62,15 +62,17 @@ public: QPalette &operator=(const QPalette &palette); #ifdef Q_COMPILER_RVALUE_REFS QPalette(QPalette &&other) Q_DECL_NOTHROW - : d(other.d), data(other.data) { other.d = Q_NULLPTR; } - inline QPalette &operator=(QPalette &&other) + : d(other.d), data(other.data) + { other.d = Q_NULLPTR; } + inline QPalette &operator=(QPalette &&other) Q_DECL_NOEXCEPT { for_faster_swapping_dont_use = other.for_faster_swapping_dont_use; qSwap(d, other.d); return *this; } #endif - void swap(QPalette &other) { + void swap(QPalette &other) Q_DECL_NOEXCEPT + { qSwap(d, other.d); qSwap(for_faster_swapping_dont_use, other.for_faster_swapping_dont_use); } diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp index 2d0458f705..3d35c4dcba 100644 --- a/src/gui/kernel/qplatformdialoghelper.cpp +++ b/src/gui/kernel/qplatformdialoghelper.cpp @@ -136,6 +136,12 @@ QVariant QPlatformDialogHelper::defaultStyleHint(QPlatformDialogHelper::StyleHi return QVariant(); } +void QPlatformDialogHelper::execModalForWindow(QWindow *parent) +{ + Q_UNUSED(parent); + exec(); +} + // Font dialog class QFontDialogOptionsPrivate : public QSharedData diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h index 8b2b9881b7..6d3a367e60 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -145,6 +145,7 @@ public: virtual QVariant styleHint(StyleHint hint) const; virtual void exec() = 0; + virtual void execModalForWindow(QWindow *parent); virtual bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) = 0; diff --git a/src/gui/kernel/qplatforminputcontextplugin_p.h b/src/gui/kernel/qplatforminputcontextplugin_p.h index 732eba3e06..d05672558d 100644 --- a/src/gui/kernel/qplatforminputcontextplugin_p.h +++ b/src/gui/kernel/qplatforminputcontextplugin_p.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE class QPlatformInputContext; -#define QPlatformInputContextFactoryInterface_iid "org.qt-project.Qt.QPlatformInputContextFactoryInterface" +#define QPlatformInputContextFactoryInterface_iid "org.qt-project.Qt.QPlatformInputContextFactoryInterface.5.1" class Q_GUI_EXPORT QPlatformInputContextPlugin : public QObject { diff --git a/src/gui/kernel/qplatformintegrationplugin.h b/src/gui/kernel/qplatformintegrationplugin.h index b5e0b1874c..89808cde5e 100644 --- a/src/gui/kernel/qplatformintegrationplugin.h +++ b/src/gui/kernel/qplatformintegrationplugin.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QPlatformIntegration; -#define QPlatformIntegrationFactoryInterface_iid "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" +#define QPlatformIntegrationFactoryInterface_iid "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.3" class Q_GUI_EXPORT QPlatformIntegrationPlugin : public QObject { diff --git a/src/gui/kernel/qplatformmenu.cpp b/src/gui/kernel/qplatformmenu.cpp index cb311b8d13..da65381931 100644 --- a/src/gui/kernel/qplatformmenu.cpp +++ b/src/gui/kernel/qplatformmenu.cpp @@ -44,4 +44,9 @@ QPlatformMenuItem *QPlatformMenu::createMenuItem() const return QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem(); } +QPlatformMenu *QPlatformMenu::createSubMenu() const +{ + return QGuiApplicationPrivate::platformTheme()->createPlatformMenu(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h index baa1e460d7..1022d0ed4a 100644 --- a/src/gui/kernel/qplatformmenu.h +++ b/src/gui/kernel/qplatformmenu.h @@ -123,6 +123,7 @@ public: virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const = 0; virtual QPlatformMenuItem *createMenuItem() const; + virtual QPlatformMenu *createSubMenu() const; Q_SIGNALS: void aboutToShow(); void aboutToHide(); diff --git a/src/gui/kernel/qplatformopenglcontext.cpp b/src/gui/kernel/qplatformopenglcontext.cpp index b9cf81b30e..f98f8a496c 100644 --- a/src/gui/kernel/qplatformopenglcontext.cpp +++ b/src/gui/kernel/qplatformopenglcontext.cpp @@ -131,6 +131,10 @@ bool QPlatformOpenGLContext::parseOpenGLVersion(const QByteArray &versionString, if (versionParts.size() >= 2) { major = versionParts.at(0).toInt(&majorOk); minor = versionParts.at(1).toInt(&minorOk); + // Nexus 6 has "OpenGL ES 3.0V@95.0 (GIT@I86da836d38)" + if (!minorOk) + if (int idx = versionParts.at(1).indexOf('V')) + minor = versionParts.at(1).left(idx).toInt(&minorOk); } else { qWarning("Unrecognized OpenGL ES version"); } diff --git a/src/gui/kernel/qshapedpixmapdndwindow.cpp b/src/gui/kernel/qshapedpixmapdndwindow.cpp index 253a09e407..8f80789fb0 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow.cpp +++ b/src/gui/kernel/qshapedpixmapdndwindow.cpp @@ -47,7 +47,7 @@ QShapedPixmapWindow::QShapedPixmapWindow() setFormat(format); setSurfaceType(RasterSurface); setFlags(Qt::ToolTip | Qt::FramelessWindowHint | - Qt::X11BypassWindowManagerHint | Qt::WindowTransparentForInput); + Qt::X11BypassWindowManagerHint | Qt::WindowTransparentForInput | Qt::WindowDoesNotAcceptFocus); create(); m_backingStore = new QBackingStore(this); } @@ -86,16 +86,14 @@ void QShapedPixmapWindow::setHotspot(const QPoint &hotspot) m_hotSpot = hotspot; } -void QShapedPixmapWindow::updateGeometry() +void QShapedPixmapWindow::updateGeometry(const QPoint &pos) { -#ifndef QT_NO_CURSOR - QRect rect(QCursor::pos() - m_hotSpot, m_pixmap.size()); if (m_pixmap.isNull()) m_backingStore->resize(QSize(1,1)); else if (m_backingStore->size() != m_pixmap.size()) m_backingStore->resize(m_pixmap.size()); - setGeometry(rect); -#endif + + setGeometry(QRect(pos - m_hotSpot, m_backingStore->size())); } void QShapedPixmapWindow::exposeEvent(QExposeEvent *) diff --git a/src/gui/kernel/qshapedpixmapdndwindow_p.h b/src/gui/kernel/qshapedpixmapdndwindow_p.h index ec56573195..fc311cff92 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow_p.h +++ b/src/gui/kernel/qshapedpixmapdndwindow_p.h @@ -63,7 +63,7 @@ public: void setPixmap(const QPixmap &pixmap); void setHotspot(const QPoint &hotspot); - void updateGeometry(); + void updateGeometry(const QPoint &pos); protected: void exposeEvent(QExposeEvent *) Q_DECL_OVERRIDE; diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index 090e88c118..b850f53014 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -201,7 +201,16 @@ void QBasicDrag::startDrag() m_drag_icon_window->setPixmap(m_drag->pixmap()); m_drag_icon_window->setHotspot(m_drag->hotSpot()); - m_drag_icon_window->updateGeometry(); + +#ifndef QT_NO_CURSOR + QPoint pos = QCursor::pos(); + if (pos.x() == int(qInf())) { + // ### fixme: no mouse pos registered. Get pos from touch... + pos = QPoint(); + } + m_drag_icon_window->updateGeometry(pos); +#endif + m_drag_icon_window->setVisible(true); enableEventFilter(); @@ -218,10 +227,10 @@ void QBasicDrag::cancel() m_drag_icon_window->setVisible(false); } -void QBasicDrag::move(const QMouseEvent *) +void QBasicDrag::move(const QMouseEvent *e) { if (m_drag) - m_drag_icon_window->updateGeometry(); + m_drag_icon_window->updateGeometry(e->globalPos()); } void QBasicDrag::drop(const QMouseEvent *) diff --git a/src/gui/kernel/qtouchdevice.cpp b/src/gui/kernel/qtouchdevice.cpp index 8737825de0..1a6e9deba8 100644 --- a/src/gui/kernel/qtouchdevice.cpp +++ b/src/gui/kernel/qtouchdevice.cpp @@ -37,6 +37,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE /*! @@ -239,4 +241,25 @@ void QTouchDevicePrivate::registerDevice(QTouchDevice *dev) deviceList()->append(dev); } +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QTouchDevice *device) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug.noquote(); + debug << "QTouchDevice("; + if (device) { + debug << '"' << device->name() << "\", type="; + QtDebugUtils::formatQEnum(debug, device->type()); + debug << ", capabilities="; + QtDebugUtils::formatQFlags(debug, device->capabilities()); + debug << ", maximumTouchPoints=" << device->maximumTouchPoints(); + } else { + debug << '0'; + } + debug << ')'; + return debug; +} +#endif // !QT_NO_DEBUG_STREAM + QT_END_NAMESPACE diff --git a/src/gui/kernel/qtouchdevice.h b/src/gui/kernel/qtouchdevice.h index f2157ce2d6..1c1fcc63aa 100644 --- a/src/gui/kernel/qtouchdevice.h +++ b/src/gui/kernel/qtouchdevice.h @@ -38,16 +38,18 @@ QT_BEGIN_NAMESPACE - +class QDebug; class QTouchDevicePrivate; class Q_GUI_EXPORT QTouchDevice { + Q_GADGET public: enum DeviceType { TouchScreen, TouchPad }; + Q_ENUM(DeviceType) enum CapabilityFlag { Position = 0x0001, @@ -58,6 +60,7 @@ public: NormalizedPosition = 0x0020, MouseEmulation = 0x0040 }; + Q_FLAG(CapabilityFlag) Q_DECLARE_FLAGS(Capabilities, CapabilityFlag) QTouchDevice(); @@ -81,6 +84,10 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(QTouchDevice::Capabilities) +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug, const QTouchDevice *); +#endif + QT_END_NAMESPACE #endif // QTOUCHDEVICE_H diff --git a/src/gui/math3d/qgenericmatrix.h b/src/gui/math3d/qgenericmatrix.h index c08faaaa8b..19809056fd 100644 --- a/src/gui/math3d/qgenericmatrix.h +++ b/src/gui/math3d/qgenericmatrix.h @@ -57,7 +57,7 @@ public: void fill(T value); - QGenericMatrix transposed() const; + QGenericMatrix transposed() const Q_REQUIRED_RESULT; QGenericMatrix& operator+=(const QGenericMatrix& other); QGenericMatrix& operator-=(const QGenericMatrix& other); diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp index 4b35ee4e79..0e73f79ac0 100644 --- a/src/gui/math3d/qquaternion.cpp +++ b/src/gui/math3d/qquaternion.cpp @@ -301,12 +301,20 @@ void QQuaternion::normalize() */ /*! - \fn QQuaternion QQuaternion::conjugate() const + \fn QQuaternion QQuaternion::conjugated() const + \since 5.5 Returns the conjugate of this quaternion, which is (-x, -y, -z, scalar). */ +/*! + \fn QQuaternion QQuaternion::conjugate() const + \obsolete + + Use conjugated() instead. +*/ + /*! Rotates \a vector with this quaternion to produce a new vector in 3D space. The following code: @@ -318,12 +326,12 @@ void QQuaternion::normalize() is equivalent to the following: \code - QVector3D result = (q * QQuaternion(0, vector) * q.conjugate()).vector(); + QVector3D result = (q * QQuaternion(0, vector) * q.conjugated()).vector(); \endcode */ QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const { - return (*this * QQuaternion(0, vector) * conjugate()).vector(); + return (*this * QQuaternion(0, vector) * conjugated()).vector(); } /*! diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h index 52c717072d..5b0006ac56 100644 --- a/src/gui/math3d/qquaternion.h +++ b/src/gui/math3d/qquaternion.h @@ -83,12 +83,15 @@ public: float length() const; float lengthSquared() const; - QQuaternion normalized() const; + QQuaternion normalized() const Q_REQUIRED_RESULT; void normalize(); inline QQuaternion inverted() const; - QQuaternion conjugate() const; + QQuaternion conjugated() const Q_REQUIRED_RESULT; +#if QT_DEPRECATED_SINCE(5, 5) + QT_DEPRECATED QQuaternion conjugate() const Q_REQUIRED_RESULT; +#endif QVector3D rotatedVector(const QVector3D& vector) const; @@ -161,12 +164,12 @@ inline QQuaternion::QQuaternion(float aScalar, float xpos, float ypos, float zpo inline bool QQuaternion::isNull() const { - return qIsNull(xp) && qIsNull(yp) && qIsNull(zp) && qIsNull(wp); + return xp == 0.0f && yp == 0.0f && zp == 0.0f && wp == 0.0f; } inline bool QQuaternion::isIdentity() const { - return qIsNull(xp) && qIsNull(yp) && qIsNull(zp) && wp == 1.0f; + return xp == 0.0f && yp == 0.0f && zp == 0.0f && wp == 1.0f; } inline float QQuaternion::x() const { return xp; } @@ -196,11 +199,18 @@ inline QQuaternion QQuaternion::inverted() const return QQuaternion(0.0f, 0.0f, 0.0f, 0.0f); } -inline QQuaternion QQuaternion::conjugate() const +inline QQuaternion QQuaternion::conjugated() const { return QQuaternion(wp, -xp, -yp, -zp); } +#if QT_DEPRECATED_SINCE(5, 5) +inline QQuaternion QQuaternion::conjugate() const +{ + return conjugated(); +} +#endif + inline QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion) { xp += quaternion.xp; @@ -230,9 +240,9 @@ inline QQuaternion &QQuaternion::operator*=(float factor) inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2) { - float ww = (q1.zp + q1.xp) * (q2.xp + q2.yp); float yy = (q1.wp - q1.yp) * (q2.wp + q2.zp); float zz = (q1.wp + q1.yp) * (q2.wp - q2.zp); + float ww = (q1.zp + q1.xp) * (q2.xp + q2.yp); float xx = ww + yy + zz; float qq = 0.5 * (xx + (q1.zp - q1.xp) * (q2.xp - q2.yp)); diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h index 20264fa84f..137142f381 100644 --- a/src/gui/math3d/qvector2d.h +++ b/src/gui/math3d/qvector2d.h @@ -75,7 +75,7 @@ public: float length() const; float lengthSquared() const; //In Qt 6 convert to inline and constexpr - QVector2D normalized() const; + QVector2D normalized() const Q_REQUIRED_RESULT; void normalize(); float distanceToPoint(const QVector2D &point) const; diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h index aa69104f55..72db8ac754 100644 --- a/src/gui/math3d/qvector4d.h +++ b/src/gui/math3d/qvector4d.h @@ -81,7 +81,7 @@ public: float length() const; float lengthSquared() const; //In Qt 6 convert to inline and constexpr - QVector4D normalized() const; + QVector4D normalized() const Q_REQUIRED_RESULT; void normalize(); QVector4D &operator+=(const QVector4D &vector); diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp index c8d33df4ba..1c008ccb42 100644 --- a/src/gui/opengl/qopengl.cpp +++ b/src/gui/opengl/qopengl.cpp @@ -47,6 +47,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE #if defined(QT_OPENGL_3) @@ -128,7 +130,7 @@ QDebug operator<<(QDebug d, const QOpenGLConfig::Gpu &g) } enum Operator { NotEqual, LessThan, LessEqualThan, Equals, GreaterThan, GreaterEqualThan }; -static const char *operators[] = {"!=", "<", "<=", "=", ">", ">="}; +static const char operators[][3] = {"!=", "<", "<=", "=", ">", ">="}; static inline QString valueKey() { return QStringLiteral("value"); } static inline QString opKey() { return QStringLiteral("op"); } @@ -474,4 +476,13 @@ QOpenGLConfig::Gpu QOpenGLConfig::Gpu::fromContext() return gpu; } +Q_GUI_EXPORT std::set *qgpu_features(const QString &filename) +{ + const QSet features = QOpenGLConfig::gpuFeatures(QOpenGLConfig::Gpu::fromContext(), filename); + std::set *result = new std::set; + foreach (const QString &feature, features) + result->insert(feature.toUtf8()); + return result; +} + QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp index 853ad8b711..7e53c01cba 100644 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -511,7 +511,7 @@ GLuint QOpenGLEngineShaderManager::getUniformLocation(Uniform id) if (uniformLocations.isEmpty()) uniformLocations.fill(GLuint(-1), NumUniforms); - static const char *uniformNames[] = { + static const char *const uniformNames[] = { "imageTexture", "patternColor", "globalOpacity", diff --git a/src/gui/opengl/qopenglextensions_p.h b/src/gui/opengl/qopenglextensions_p.h index ff5d79566c..7def687f49 100644 --- a/src/gui/opengl/qopenglextensions_p.h +++ b/src/gui/opengl/qopenglextensions_p.h @@ -76,6 +76,9 @@ public: void (QOPENGLF_APIENTRYP TexStorage2D)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height); private: + bool init(); + QFunctionPointer resolve(const char *name); + QLibrary m_gl; }; diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index c60532b90b..b9d674fd3b 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -39,6 +39,10 @@ #include #include +#ifdef Q_OS_IOS +#include +#endif + #ifndef GL_FRAMEBUFFER_SRGB_CAPABLE_EXT #define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA #endif @@ -3202,35 +3206,53 @@ static void QOPENGLF_APIENTRY qopenglfResolveVertexAttribPointer(GLuint indx, GL Q_GLOBAL_STATIC(QOpenGLES3Helper, qgles3Helper) +bool QOpenGLES3Helper::init() +{ +#ifndef Q_OS_IOS +# ifdef Q_OS_WIN +# ifndef QT_DEBUG + m_gl.setFileName(QStringLiteral("libGLESv2")); +# else + m_gl.setFileName(QStringLiteral("libGLESv2d")); +# endif +# else + m_gl.setFileName(QStringLiteral("GLESv2")); +# endif // Q_OS_WIN + return m_gl.load(); +#else + return true; +#endif // Q_OS_IOS +} + +QFunctionPointer QOpenGLES3Helper::resolve(const char *name) +{ +#ifdef Q_OS_IOS + return QFunctionPointer(dlsym(RTLD_DEFAULT, name)); +#else + return m_gl.resolve(name); +#endif +} + QOpenGLES3Helper::QOpenGLES3Helper() { -#ifdef Q_OS_WIN -#ifdef QT_DEBUG - m_gl.setFileName(QStringLiteral("libGLESv2")); -#else - m_gl.setFileName(QStringLiteral("libGLESv2d")); -#endif -#else - m_gl.setFileName(QStringLiteral("GLESv2")); -#endif - if (m_gl.load()) { - MapBufferRange = (GLvoid* (QOPENGLF_APIENTRYP)(GLenum, qopengl_GLintptr, qopengl_GLsizeiptr, GLbitfield)) m_gl.resolve("glMapBufferRange"); - UnmapBuffer = (GLboolean (QOPENGLF_APIENTRYP)(GLenum)) m_gl.resolve("glUnmapBuffer"); - BlitFramebuffer = (void (QOPENGLF_APIENTRYP)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum)) m_gl.resolve("glBlitFramebuffer"); - RenderbufferStorageMultisample = (void (QOPENGLF_APIENTRYP)(GLenum, GLsizei, GLenum, GLsizei, GLsizei)) m_gl.resolve("glRenderbufferStorageMultisample"); + if (init()) { + MapBufferRange = (GLvoid* (QOPENGLF_APIENTRYP)(GLenum, qopengl_GLintptr, qopengl_GLsizeiptr, GLbitfield)) resolve("glMapBufferRange"); + UnmapBuffer = (GLboolean (QOPENGLF_APIENTRYP)(GLenum)) resolve("glUnmapBuffer"); + BlitFramebuffer = (void (QOPENGLF_APIENTRYP)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum)) resolve("glBlitFramebuffer"); + RenderbufferStorageMultisample = (void (QOPENGLF_APIENTRYP)(GLenum, GLsizei, GLenum, GLsizei, GLsizei)) resolve("glRenderbufferStorageMultisample"); - GenVertexArrays = (void (QOPENGLF_APIENTRYP)(GLsizei, GLuint *)) m_gl.resolve("glGenVertexArrays"); - DeleteVertexArrays = (void (QOPENGLF_APIENTRYP)(GLsizei, const GLuint *)) m_gl.resolve("glDeleteVertexArrays"); - BindVertexArray = (void (QOPENGLF_APIENTRYP)(GLuint)) m_gl.resolve("glBindVertexArray"); - IsVertexArray = (GLboolean (QOPENGLF_APIENTRYP)(GLuint)) m_gl.resolve("glIsVertexArray"); + GenVertexArrays = (void (QOPENGLF_APIENTRYP)(GLsizei, GLuint *)) resolve("glGenVertexArrays"); + DeleteVertexArrays = (void (QOPENGLF_APIENTRYP)(GLsizei, const GLuint *)) resolve("glDeleteVertexArrays"); + BindVertexArray = (void (QOPENGLF_APIENTRYP)(GLuint)) resolve("glBindVertexArray"); + IsVertexArray = (GLboolean (QOPENGLF_APIENTRYP)(GLuint)) resolve("glIsVertexArray"); - TexImage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) m_gl.resolve("glTexImage3D"); - TexSubImage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) m_gl.resolve("glTexSubImage3D"); - CompressedTexImage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) m_gl.resolve("glCompressedTexImage3D"); - CompressedTexSubImage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) m_gl.resolve("glCompressedTexSubImage3D"); + TexImage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *)) resolve("glTexImage3D"); + TexSubImage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *)) resolve("glTexSubImage3D"); + CompressedTexImage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid *)) resolve("glCompressedTexImage3D"); + CompressedTexSubImage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid *)) resolve("glCompressedTexSubImage3D"); - TexStorage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei)) m_gl.resolve("glTexStorage3D"); - TexStorage2D = (void (QOPENGLF_APIENTRYP)(GLenum, GLsizei, GLenum, GLsizei, GLsizei)) m_gl.resolve("glTexStorage2D"); + TexStorage3D = (void (QOPENGLF_APIENTRYP)(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei)) resolve("glTexStorage3D"); + TexStorage2D = (void (QOPENGLF_APIENTRYP)(GLenum, GLsizei, GLenum, GLsizei, GLsizei)) resolve("glTexStorage2D"); if (!MapBufferRange || !GenVertexArrays || !TexImage3D || !TexStorage3D) qFatal("OpenGL ES 3.0 entry points not found"); @@ -3568,7 +3590,7 @@ void QOpenGLExtensions::flushShared() d->flushIsSufficientToSyncContexts = false; // default to false, not guaranteed by the spec const char *vendor = (const char *) glGetString(GL_VENDOR); if (vendor) { - static const char *flushEnough[] = { "Apple", "ATI", "Intel", "NVIDIA" }; + static const char *const flushEnough[] = { "Apple", "ATI", "Intel", "NVIDIA" }; for (size_t i = 0; i < sizeof(flushEnough) / sizeof(const char *); ++i) { if (strstr(vendor, flushEnough[i])) { d->flushIsSufficientToSyncContexts = true; diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 5bf8387400..670717c5f1 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -999,7 +999,7 @@ bool QBrush::operator==(const QBrush &b) const */ QDebug operator<<(QDebug dbg, const QBrush &b) { - static const char *BRUSH_STYLES[] = { + static const char *const BRUSH_STYLES[] = { "NoBrush", "SolidPattern", "Dense1Pattern", diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h index a3b88a50ef..ceb95f5676 100644 --- a/src/gui/painting/qbrush.h +++ b/src/gui/painting/qbrush.h @@ -73,10 +73,11 @@ public: ~QBrush(); QBrush &operator=(const QBrush &brush); #ifdef Q_COMPILER_RVALUE_REFS - inline QBrush &operator=(QBrush &&other) + inline QBrush &operator=(QBrush &&other) Q_DECL_NOEXCEPT { qSwap(d, other.d); return *this; } #endif - inline void swap(QBrush &other) { qSwap(d, other.d); } + inline void swap(QBrush &other) Q_DECL_NOEXCEPT + { qSwap(d, other.d); } operator QVariant() const; diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index b33d7a74fc..f1ceb464c8 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -729,8 +729,8 @@ void QColor::setHsv(int h, int s, int v, int a) saturation, lightness, and alpha-channel (transparency) components of the color's HSL value. - These components can be retrieved individually using the hueHslF(), - saturationHslF(), lightnessF() and alphaF() functions. + These components can be retrieved individually using the hslHueF(), + hslSaturationF(), lightnessF() and alphaF() functions. \sa setHsl() */ @@ -759,8 +759,8 @@ void QColor::getHslF(qreal *h, qreal *s, qreal *l, qreal *a) const saturation, lightness, and alpha-channel (transparency) components of the color's HSL value. - These components can be retrieved individually using the hueHsl(), - saturationHsl(), lightness() and alpha() functions. + These components can be retrieved individually using the hslHue(), + hslSaturation(), lightness() and alpha() functions. \sa setHsl() */ diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index e46e997f1d..7b03cc00ff 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -944,7 +944,7 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8 }; -FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { +const FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { 0, // BPPNone fetchPixels, // BPP1MSB fetchPixels, // BPP1LSB @@ -954,7 +954,7 @@ FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { fetchPixels // BPP32 }; -StorePixelsFunc qStorePixels[QPixelLayout::BPPCount] = { +const StorePixelsFunc qStorePixels[QPixelLayout::BPPCount] = { 0, // BPPNone storePixels, // BPP1MSB storePixels, // BPP1LSB @@ -966,7 +966,7 @@ StorePixelsFunc qStorePixels[QPixelLayout::BPPCount] = { typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index); -FetchPixelFunc qFetchPixel[QPixelLayout::BPPCount] = { +static const FetchPixelFunc qFetchPixel[QPixelLayout::BPPCount] = { 0, // BPPNone fetchPixel, // BPP1MSB fetchPixel, // BPP1LSB diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index f8865a6f7e..179900ddd2 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -1142,8 +1142,8 @@ typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *sr typedef void (QT_FASTCALL *StorePixelsFunc)(uchar *dest, const uint *src, int index, int count); extern QPixelLayout qPixelLayouts[QImage::NImageFormats]; -extern FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount]; -extern StorePixelsFunc qStorePixels[QPixelLayout::BPPCount]; +extern const FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount]; +extern const StorePixelsFunc qStorePixels[QPixelLayout::BPPCount]; diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 5f1b25e189..867c64c5e0 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -38,22 +38,6 @@ QT_BEGIN_NAMESPACE -typedef void (*qt_qimageScaleFunc)(QImageScale::QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow); - -static void qt_qimageScaleAARGB(QImageScale::QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow); - -static void qt_qimageScaleAARGBA(QImageScale::QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow); - -qt_qimageScaleFunc qt_qimageScaleArgb = qt_qimageScaleAARGBA; -qt_qimageScaleFunc qt_qimageScaleRgb = qt_qimageScaleAARGB; - - /* * Copyright (C) 2004, 2005 Daniel M. Duley * @@ -93,6 +77,8 @@ qt_qimageScaleFunc qt_qimageScaleRgb = qt_qimageScaleAARGB; * * Changes include formatting, namespaces and other C++'ings, removal of old * #ifdef'ed code, and removal of unneeded border calculation code. + * Later the code has been refactored and an SSE4.1 optimizated path have been + * added instead of the removed MMX assembler. * * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code * is by Willem Monsuwe . All other modifications are @@ -115,21 +101,14 @@ using namespace QImageScale; // Code ported from Imlib... // -// FIXME: replace with qRed, etc... These work on pointers to pixels, not -// pixel values -#define A_VAL(p) (qAlpha(*p)) -#define R_VAL(p) (qRed(*p)) -#define G_VAL(p) (qGreen(*p)) -#define B_VAL(p) (qBlue(*p)) - const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, - int sw, int sh, int dh) + int sw, int sh, int dh) { const unsigned int **p; int j = 0, rv = 0; qint64 val, inc; - if(dh < 0){ + if (dh < 0) { dh = -dh; rv = 1; } @@ -157,7 +136,7 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) int *p, j = 0, rv = 0; qint64 val, inc; - if(dw < 0){ + if (dw < 0) { dw = -dw; rv = 1; } @@ -178,25 +157,23 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) p[dw - i - 1] = tmp; } } - return(p); + return p; } int* QImageScale::qimageCalcApoints(int s, int d, int up) { int *p, j = 0, rv = 0; - if(d < 0){ + if (d < 0) { rv = 1; d = -d; } p = new int[d]; - /* scaling up */ - if(up){ - qint64 val, inc; - - val = 0x8000 * s / d - 0x8000; - inc = (((qint64)s) << 16) / d; + if (up) { + /* scaling up */ + qint64 val = 0x8000 * s / d - 0x8000; + qint64 inc = (((qint64)s) << 16) / d; for (int i = 0; i < d; i++) { int pos = val >> 16; if (pos < 0) @@ -207,9 +184,8 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00); val += inc; } - } - /* scaling down */ - else { + } else { + /* scaling down */ qint64 val = 0; qint64 inc = (((qint64)s) << 16) / d; int Cp = (((d << 14) + s - 1) / s); @@ -220,7 +196,7 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) val += inc; } } - if(rv){ + if (rv) { int tmp; for (int i = d / 2; --i >= 0; ) { tmp = p[i]; @@ -233,7 +209,7 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi) { - if(isi){ + if (isi) { delete[] isi->xpoints; delete[] isi->ypoints; delete[] isi->xapoints; @@ -254,28 +230,28 @@ QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, sch = dh * qlonglong(img.height()) / sh; isi = new QImageScaleInfo; - if(!isi) + if (!isi) return 0; memset(isi, 0, sizeof(QImageScaleInfo)); isi->xup_yup = (qAbs(dw) >= sw) + ((qAbs(dh) >= sh) << 1); isi->xpoints = qimageCalcXPoints(img.width(), scw); - if(!isi->xpoints) - return(qimageFreeScaleInfo(isi)); + if (!isi->xpoints) + return qimageFreeScaleInfo(isi); isi->ypoints = qimageCalcYPoints((const unsigned int *)img.scanLine(0), img.bytesPerLine() / 4, img.height(), sch); if (!isi->ypoints) - return(qimageFreeScaleInfo(isi)); - if(aa) { + return qimageFreeScaleInfo(isi); + if (aa) { isi->xapoints = qimageCalcApoints(img.width(), scw, isi->xup_yup & 1); - if(!isi->xapoints) - return(qimageFreeScaleInfo(isi)); + if (!isi->xapoints) + return qimageFreeScaleInfo(isi); isi->yapoints = qimageCalcApoints(img.height(), sch, isi->xup_yup & 2); - if(!isi->yapoints) - return(qimageFreeScaleInfo(isi)); + if (!isi->yapoints) + return qimageFreeScaleInfo(isi); } - return(isi); + return isi; } @@ -349,7 +325,7 @@ static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, int dh, int dow, int sow) { /* scaling up both ways */ - if (isi->xup_yup == 3){ + if (isi->xup_yup == 3) { qt_qimageScaleAARGBA_up_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } /* if we're scaling down vertically */ @@ -381,46 +357,25 @@ static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, } } -inline static void qt_qimageScaleAARGBA_helper_x(const unsigned int *pix, int xap, int Cx, int &r, int &g, int &b, int &a) +inline static void qt_qimageScaleAARGBA_helper(const unsigned int *pix, int xyap, int Cxy, int step, int &r, int &g, int &b, int &a) { - r = R_VAL(pix) * xap; - g = G_VAL(pix) * xap; - b = B_VAL(pix) * xap; - a = A_VAL(pix) * xap; + r = qRed(*pix) * xyap; + g = qGreen(*pix) * xyap; + b = qBlue(*pix) * xyap; + a = qAlpha(*pix) * xyap; int j; - for (j = (1 << 14) - xap; j > Cx; j -= Cx ){ - pix++; - r += R_VAL(pix) * Cx; - g += G_VAL(pix) * Cx; - b += B_VAL(pix) * Cx; - a += A_VAL(pix) * Cx; + for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy) { + pix += step; + r += qRed(*pix) * Cxy; + g += qGreen(*pix) * Cxy; + b += qBlue(*pix) * Cxy; + a += qAlpha(*pix) * Cxy; } - pix++; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - a += A_VAL(pix) * j; -} - -inline static void qt_qimageScaleAARGBA_helper_y(const unsigned int *pix, int yap, int Cy, int sow, int &r, int &g, int &b, int &a) -{ - r = R_VAL(pix) * yap; - g = G_VAL(pix) * yap; - b = B_VAL(pix) * yap; - a = A_VAL(pix) * yap; - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy ){ - pix += sow; - r += R_VAL(pix) * Cy; - g += G_VAL(pix) * Cy; - b += B_VAL(pix) * Cy; - a += A_VAL(pix) * Cy; - } - pix += sow; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - a += A_VAL(pix) * j; + pix += step; + r += qRed(*pix) * j; + g += qGreen(*pix) * j; + b += qBlue(*pix) * j; + a += qAlpha(*pix) * j; } static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, @@ -443,12 +398,12 @@ static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int for (int x = dxx; x < end; x++) { const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; int r, g, b, a; - qt_qimageScaleAARGBA_helper_y(sptr, yap, Cy, sow, r, g, b, a); + qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a); int xap = xapoints[x]; if (xap > 0) { int rr, gg, bb, aa; - qt_qimageScaleAARGBA_helper_y(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); r = r * (256 - xap); g = g * (256 - xap); @@ -484,12 +439,12 @@ static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; int r, g, b, a; - qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, r, g, b, a); + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a); int yap = yapoints[dyy + y]; if (yap > 0) { int rr, gg, bb, aa; - qt_qimageScaleAARGBA_helper_x(sptr + sow, xap, Cx, rr, gg, bb, aa); + qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa); r = r * (256 - yap); g = g * (256 - yap); @@ -528,7 +483,7 @@ static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *des const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; int rx, gx, bx, ax; - qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); int r = ((rx>>4) * yap); int g = ((gx>>4) * yap); @@ -538,14 +493,14 @@ static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *des int j; for (j = (1 << 14) - yap; j > Cy; j -= Cy) { sptr += sow; - qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); r += ((rx>>4) * Cy); g += ((gx>>4) * Cy); b += ((bx>>4) * Cy); a += ((ax>>4) * Cy); } sptr += sow; - qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax); r += ((rx>>4) * j); g += ((gx>>4) * j); @@ -609,40 +564,22 @@ static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest, } -inline static void qt_qimageScaleAARGB_helper_x(const unsigned int *pix, int xap, int Cx, int &r, int &g, int &b) +inline static void qt_qimageScaleAARGB_helper(const unsigned int *pix, int xyap, int Cxy, int step, int &r, int &g, int &b) { - r = R_VAL(pix) * xap; - g = G_VAL(pix) * xap; - b = B_VAL(pix) * xap; + r = qRed(*pix) * xyap; + g = qGreen(*pix) * xyap; + b = qBlue(*pix) * xyap; int j; - for (j = (1 << 14) - xap; j > Cx; j -= Cx ){ - pix++; - r += R_VAL(pix) * Cx; - g += G_VAL(pix) * Cx; - b += B_VAL(pix) * Cx; + for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy) { + pix += step; + r += qRed(*pix) * Cxy; + g += qGreen(*pix) * Cxy; + b += qBlue(*pix) * Cxy; } - pix++; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; -} - -inline static void qt_qimageScaleAARGB_helper_y(const unsigned int *pix, int yap, int Cy, int sow, int &r, int &g, int &b) -{ - r = R_VAL(pix) * yap; - g = G_VAL(pix) * yap; - b = B_VAL(pix) * yap; - int j; - for (j = (1 << 14) - yap; j > Cy; j -= Cy ){ - pix += sow; - r += R_VAL(pix) * Cy; - g += G_VAL(pix) * Cy; - b += B_VAL(pix) * Cy; - } - pix += sow; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; + pix += step; + r += qRed(*pix) * j; + g += qGreen(*pix) * j; + b += qBlue(*pix) * j; } static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, @@ -665,12 +602,12 @@ static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int * for (int x = dxx; x < end; x++) { const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; int r, g, b; - qt_qimageScaleAARGB_helper_y(sptr, yap, Cy, sow, r, g, b); + qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b); int xap = xapoints[x]; if (xap > 0) { int rr, bb, gg; - qt_qimageScaleAARGB_helper_y(sptr + 1, yap, Cy, sow, rr, gg, bb); + qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb); r = r * (256 - xap); g = g * (256 - xap); @@ -704,12 +641,12 @@ static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int * const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; int r, g, b; - qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, r, g, b); + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b); int yap = yapoints[dyy + y]; if (yap > 0) { int rr, bb, gg; - qt_qimageScaleAARGB_helper_x(sptr + sow, xap, Cx, rr, gg, bb); + qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb); r = r * (256 - yap); g = g * (256 - yap); @@ -745,7 +682,7 @@ static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; int rx, gx, bx; - qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); int r = (rx >> 4) * yap; int g = (gx >> 4) * yap; @@ -754,14 +691,14 @@ static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest int j; for (j = (1 << 14) - yap; j > Cy; j -= Cy) { sptr += sow; - qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); r += (rx >> 4) * Cy; g += (gx >> 4) * Cy; b += (bx >> 4) * Cy; } sptr += sow; - qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx); r += (rx >> 4) * j; g += (gx >> 4) * j; @@ -794,11 +731,11 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh) } if (src.hasAlphaChannel()) - qt_qimageScaleArgb(scaleinfo, (unsigned int *)buffer.scanLine(0), - 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4); + qt_qimageScaleAARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0), + 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4); else - qt_qimageScaleRgb(scaleinfo, (unsigned int *)buffer.scanLine(0), - 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4); + qt_qimageScaleAARGB(scaleinfo, (unsigned int *)buffer.scanLine(0), + 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4); qimageFreeScaleInfo(scaleinfo); return buffer; diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp index 565ea4daa1..303e0fd980 100644 --- a/src/gui/painting/qimagescale_sse4.cpp +++ b/src/gui/painting/qimagescale_sse4.cpp @@ -41,33 +41,17 @@ QT_BEGIN_NAMESPACE using namespace QImageScale; -inline static __m128i qt_qimageScaleAARGBA_helper_x(const unsigned int *pix, int xap, int Cx, const __m128i vxap, const __m128i vCx) +inline static __m128i qt_qimageScaleAARGBA_helper(const unsigned int *pix, int xyap, int Cxy, int step, const __m128i vxyap, const __m128i vCxy) { __m128i vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); - __m128i vx = _mm_mullo_epi32(vpix, vxap); + __m128i vx = _mm_mullo_epi32(vpix, vxyap); int i; - for (i = (1 << 14) - xap; i > Cx; i -= Cx) { - pix++; + for (i = (1 << 14) - xyap; i > Cxy; i -= Cxy) { + pix += step; vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); - vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCx)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCxy)); } - pix++; - vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); - vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, _mm_set1_epi32(i))); - return vx; -} - -inline static __m128i qt_qimageScaleAARGBA_helper_y(const unsigned int *pix, int yap, int Cy, int sow, const __m128i vyap, const __m128i vCy) -{ - __m128i vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); - __m128i vx = _mm_mullo_epi32(vpix, vyap); - int i; - for (i = (1 << 14) - yap; i > Cy; i -= Cy) { - pix += sow; - vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); - vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCy)); - } - pix += sow; + pix += step; vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, _mm_set1_epi32(i))); return vx; @@ -97,13 +81,13 @@ void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *d unsigned int *dptr = dest + dx + ((y + dy) * dow); for (int x = dxx; x < end; x++) { const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; - __m128i vx = qt_qimageScaleAARGBA_helper_y(sptr, yap, Cy, sow, vyap, vCy); + __m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy); int xap = xapoints[x]; if (xap > 0) { const __m128i vxap = _mm_set1_epi32(xap); const __m128i vinvxap = _mm_sub_epi32(v256, vxap); - __m128i vr = qt_qimageScaleAARGBA_helper_y(sptr + 1, yap, Cy, sow, vyap, vCy); + __m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy); vx = _mm_mullo_epi32(vx, vinvxap); vr = _mm_mullo_epi32(vr, vxap); @@ -145,13 +129,13 @@ void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *d const __m128i vxap = _mm_set1_epi32(xap); const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; - __m128i vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); int yap = yapoints[dyy + y]; if (yap > 0) { const __m128i vyap = _mm_set1_epi32(yap); const __m128i vinvyap = _mm_sub_epi32(v256, vyap); - __m128i vr = qt_qimageScaleAARGBA_helper_x(sptr + sow, xap, Cx, vxap, vCx); + __m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx); vx = _mm_mullo_epi32(vx, vinvyap); vr = _mm_mullo_epi32(vr, vyap); @@ -194,17 +178,17 @@ void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, const __m128i vxap = _mm_set1_epi32(xap); const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; - __m128i vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap); int j; for (j = (1 << 14) - yap; j > Cy; j -= Cy) { sptr += sow; - vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy)); } sptr += sow; - vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx); vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j))); vr = _mm_srli_epi32(vr, 24); diff --git a/src/gui/painting/qpaintdevice.cpp b/src/gui/painting/qpaintdevice.cpp index 36e0bbe223..bbf8e8f170 100644 --- a/src/gui/painting/qpaintdevice.cpp +++ b/src/gui/painting/qpaintdevice.cpp @@ -35,7 +35,7 @@ QT_BEGIN_NAMESPACE -QPaintDevice::QPaintDevice() +QPaintDevice::QPaintDevice() Q_DECL_NOEXCEPT { reserved = 0; painters = 0; diff --git a/src/gui/painting/qpaintdevice.h b/src/gui/painting/qpaintdevice.h index 7c756c66de..4eb972786b 100644 --- a/src/gui/painting/qpaintdevice.h +++ b/src/gui/painting/qpaintdevice.h @@ -80,7 +80,7 @@ public: int depth() const { return metric(PdmDepth); } protected: - QPaintDevice(); + QPaintDevice() Q_DECL_NOEXCEPT; virtual int metric(PaintDeviceMetric metric) const; virtual void initPainter(QPainter *painter) const; virtual QPaintDevice *redirected(QPoint *offset) const; diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 0f80cd18a0..f00bc8d9df 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -238,7 +238,7 @@ bool QPaintEngineExPrivate::hasClipOperations() const * */ -static QPainterPath::ElementType qpaintengineex_ellipse_types[] = { +static const QPainterPath::ElementType qpaintengineex_ellipse_types[] = { QPainterPath::MoveToElement, QPainterPath::CurveToElement, QPainterPath::CurveToDataElement, @@ -257,7 +257,7 @@ static QPainterPath::ElementType qpaintengineex_ellipse_types[] = { QPainterPath::CurveToDataElement }; -static QPainterPath::ElementType qpaintengineex_line_types_16[] = { +static const QPainterPath::ElementType qpaintengineex_line_types_16[] = { QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::MoveToElement, QPainterPath::LineToElement, @@ -276,7 +276,7 @@ static QPainterPath::ElementType qpaintengineex_line_types_16[] = { QPainterPath::MoveToElement, QPainterPath::LineToElement }; -static QPainterPath::ElementType qpaintengineex_rect4_types_32[] = { +static const QPainterPath::ElementType qpaintengineex_rect4_types_32[] = { QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 1 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 2 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 3 @@ -312,7 +312,7 @@ static QPainterPath::ElementType qpaintengineex_rect4_types_32[] = { }; -static QPainterPath::ElementType qpaintengineex_roundedrect_types[] = { +static const QPainterPath::ElementType qpaintengineex_roundedrect_types[] = { QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::CurveToElement, diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index e3c6eabbc3..e2f267d7ee 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -521,7 +521,7 @@ void QPainterPath::setElementPositionAt(int i, qreal x, qreal y) /*! Constructs an empty QPainterPath object. */ -QPainterPath::QPainterPath() +QPainterPath::QPainterPath() Q_DECL_NOEXCEPT : d_ptr(0) { } @@ -3057,20 +3057,19 @@ qreal QPainterPath::slopeAtPercent(qreal t) const //tangent line qreal slope = 0; -#define SIGN(x) ((x < 0)?-1:1) if (m1) slope = m2/m1; else { - //windows doesn't define INFINITY :( -#ifdef INFINITY - slope = INFINITY*SIGN(m2); -#else - if (sizeof(qreal) == sizeof(double)) { - return 1.79769313486231570e+308; + if (std::numeric_limits::has_infinity) { + slope = (m2 < 0) ? -std::numeric_limits::infinity() + : std::numeric_limits::infinity(); } else { - return ((qreal)3.40282346638528860e+38); + if (sizeof(qreal) == sizeof(double)) { + return 1.79769313486231570e+308; + } else { + return ((qreal)3.40282346638528860e+38); + } } -#endif } return slope; diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h index eb32782a96..4a7bd98234 100644 --- a/src/gui/painting/qpainterpath.h +++ b/src/gui/painting/qpainterpath.h @@ -81,16 +81,16 @@ public: inline bool operator!=(const Element &e) const { return !operator==(e); } }; - QPainterPath(); + QPainterPath() Q_DECL_NOEXCEPT; explicit QPainterPath(const QPointF &startPoint); QPainterPath(const QPainterPath &other); QPainterPath &operator=(const QPainterPath &other); #ifdef Q_COMPILER_RVALUE_REFS - inline QPainterPath &operator=(QPainterPath &&other) + inline QPainterPath &operator=(QPainterPath &&other) Q_DECL_NOEXCEPT { qSwap(d_ptr, other.d_ptr); return *this; } #endif ~QPainterPath(); - inline void swap(QPainterPath &other) { d_ptr.swap(other.d_ptr); } + inline void swap(QPainterPath &other) Q_DECL_NOEXCEPT { d_ptr.swap(other.d_ptr); } void closeSubpath(); @@ -147,8 +147,8 @@ public: void translate(qreal dx, qreal dy); inline void translate(const QPointF &offset); - QPainterPath translated(qreal dx, qreal dy) const; - inline QPainterPath translated(const QPointF &offset) const; + QPainterPath translated(qreal dx, qreal dy) const Q_REQUIRED_RESULT; + inline QPainterPath translated(const QPointF &offset) const Q_REQUIRED_RESULT; QRectF boundingRect() const; QRectF controlPointRect() const; @@ -158,7 +158,7 @@ public: bool isEmpty() const; - QPainterPath toReversed() const; + QPainterPath toReversed() const Q_REQUIRED_RESULT; QList toSubpathPolygons(const QMatrix &matrix = QMatrix()) const; QList toFillPolygons(const QMatrix &matrix = QMatrix()) const; QPolygonF toFillPolygon(const QMatrix &matrix = QMatrix()) const; @@ -178,12 +178,12 @@ public: bool intersects(const QPainterPath &p) const; bool contains(const QPainterPath &p) const; - QPainterPath united(const QPainterPath &r) const; - QPainterPath intersected(const QPainterPath &r) const; - QPainterPath subtracted(const QPainterPath &r) const; - QPainterPath subtractedInverted(const QPainterPath &r) const; + QPainterPath united(const QPainterPath &r) const Q_REQUIRED_RESULT; + QPainterPath intersected(const QPainterPath &r) const Q_REQUIRED_RESULT; + QPainterPath subtracted(const QPainterPath &r) const Q_REQUIRED_RESULT; + QPainterPath subtractedInverted(const QPainterPath &r) const Q_REQUIRED_RESULT; - QPainterPath simplified() const; + QPainterPath simplified() const Q_REQUIRED_RESULT; bool operator==(const QPainterPath &other) const; bool operator!=(const QPainterPath &other) const; diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 3f2ebb92a0..6ea0800538 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -384,7 +384,7 @@ QByteArray QPdf::generateDashes(const QPen &pen) -static const char* pattern_for_brush[] = { +static const char* const pattern_for_brush[] = { 0, // NoBrush 0, // SolidPattern "0 J\n" diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 24ea3f4cdd..62492980de 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -83,9 +83,10 @@ public: struct QBackingstoreTextureInfo { - QWidget *widget; // may be null + void *source; // may be null GLuint textureId; QRect rect; + QRect clipRect; QPlatformTextureList::Flags flags; }; @@ -124,10 +125,10 @@ GLuint QPlatformTextureList::textureId(int index) const return d->textures.at(index).textureId; } -QWidget *QPlatformTextureList::widget(int index) +void *QPlatformTextureList::source(int index) { Q_D(const QPlatformTextureList); - return d->textures.at(index).widget; + return d->textures.at(index).source; } QPlatformTextureList::Flags QPlatformTextureList::flags(int index) const @@ -142,6 +143,12 @@ QRect QPlatformTextureList::geometry(int index) const return d->textures.at(index).rect; } +QRect QPlatformTextureList::clipRect(int index) const +{ + Q_D(const QPlatformTextureList); + return d->textures.at(index).clipRect; +} + void QPlatformTextureList::lock(bool on) { Q_D(QPlatformTextureList); @@ -157,13 +164,15 @@ bool QPlatformTextureList::isLocked() const return d->locked; } -void QPlatformTextureList::appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags) +void QPlatformTextureList::appendTexture(void *source, GLuint textureId, const QRect &geometry, + const QRect &clipRect, Flags flags) { Q_D(QPlatformTextureList); QBackingstoreTextureInfo bi; - bi.widget = widget; + bi.source = source; bi.textureId = textureId; bi.rect = geometry; + bi.clipRect = clipRect; bi.flags = flags; d->textures.append(bi); } @@ -198,7 +207,7 @@ void QPlatformTextureList::clear() #ifndef QT_NO_OPENGL -static QRect deviceRect(const QRect &rect, QWindow *window) +static inline QRect deviceRect(const QRect &rect, QWindow *window) { QRect deviceRect(rect.topLeft() * window->devicePixelRatio(), rect.size() * window->devicePixelRatio()); @@ -219,6 +228,32 @@ static QRegion deviceRegion(const QRegion ®ion, QWindow *window) return deviceRegion; } +static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) +{ + return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1, + topLeftRect.width(), topLeftRect.height()); +} + +static void blit(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect, + QOpenGLTextureBlitter *blitter) +{ + const QRect rectInWindow = textures->geometry(idx); + QRect clipRect = textures->clipRect(idx); + if (clipRect.isEmpty()) + clipRect = QRect(QPoint(0, 0), rectInWindow.size()); + const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft()); + const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height()); + + const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(deviceRect(clippedRectInWindow, window), + deviceWindowRect); + + const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window), + deviceRect(rectInWindow, window).size(), + QOpenGLTextureBlitter::OriginBottomLeft); + + blitter->blit(textures->textureId(idx), target, source); +} + /*! Flushes the given \a region from the specified \a window onto the screen, and composes it with the specified \a textures. @@ -254,15 +289,12 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i d_ptr->blitter->bind(); - QRect windowRect(QPoint(), window->size() * window->devicePixelRatio()); + const QRect deviceWindowRect = deviceRect(QRect(QPoint(), window->size()), window); // Textures for renderToTexture widgets. for (int i = 0; i < textures->count(); ++i) { - if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { - QRect targetRect = deviceRect(textures->geometry(i), window); - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); - d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); - } + if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) + blit(textures, i, window, deviceWindowRect, d_ptr->blitter); } funcs->glEnable(GL_BLEND); @@ -272,6 +304,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // semi-transparency even when it is not wanted. funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + // Backingstore texture with the normal widgets. GLuint textureId = 0; QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft; if (QPlatformGraphicsBuffer *graphicsBuffer = this->graphicsBuffer()) { @@ -307,12 +340,15 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i origin = QOpenGLTextureBlitter::OriginBottomLeft; textureId = d_ptr->textureId; } else { - // Backingstore texture with the normal widgets. - textureId = toTexture(deviceRegion(region, window), &d_ptr->textureSize, &d_ptr->needsSwizzle); + TextureFlags flags = 0; + textureId = toTexture(deviceRegion(region, window), &d_ptr->textureSize, &flags); + d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0; + if (flags & TextureFlip) + origin = QOpenGLTextureBlitter::OriginBottomLeft; } if (textureId) { - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), windowRect); + QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), deviceWindowRect); if (d_ptr->needsSwizzle) d_ptr->blitter->setSwizzleRB(true); d_ptr->blitter->blit(textureId, target, origin); @@ -322,11 +358,8 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. for (int i = 0; i < textures->count(); ++i) { - if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { - QRect targetRect = deviceRect(textures->geometry(i), window); - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); - d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); - } + if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) + blit(textures, i, window, deviceWindowRect, d_ptr->blitter); } funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -354,43 +387,55 @@ QImage QPlatformBackingStore::toImage() const backingstore as an OpenGL texture. \a dirtyRegion is the part of the backingstore which may have changed since the last call to this function. The caller of this function must ensure that there is a current context. + The size of the texture is returned in \a textureSize. The ownership of the texture is not transferred. The caller must not store the return value between calls, but instead call this function before each use. - The default implementation returns a cached texture if \a dirtyRegion is - empty and the window has not been resized, otherwise it retrieves the - content using toImage() and performs a texture upload. + The default implementation returns a cached texture if \a dirtyRegion is empty and + \a textureSize matches the backingstore size, otherwise it retrieves the content using + toImage() and performs a texture upload. This works only if the value of \a textureSize + is preserved between the calls to this function. - If the red and blue components have to swapped, \a needsSwizzle will be set to \c true. - This allows creating textures from images in formats like QImage::Format_RGB32 without - any further image conversion. Instead, the swizzling will be done in the shaders when - performing composition. Other formats, that do not need such swizzling due to being - already byte ordered RGBA, for example QImage::Format_RGBA8888, must result in having \a - needsSwizzle set to false. + If the red and blue components have to swapped, \a flags will be set to include \c + TextureSwizzle. This allows creating textures from images in formats like + QImage::Format_RGB32 without any further image conversion. Instead, the swizzling will + be done in the shaders when performing composition. Other formats, that do not need + such swizzling due to being already byte ordered RGBA, for example + QImage::Format_RGBA8888, must result in having \a needsSwizzle set to false. + + If the image has to be flipped (e.g. because the texture is attached to an FBO), \a + flags will be set to include \c TextureFlip. */ -GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, bool *needsSwizzle) const +GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const { + Q_ASSERT(textureSize); + Q_ASSERT(flags); + QImage image = toImage(); QSize imageSize = image.size(); - if (imageSize.isEmpty()) - return 0; - bool resized = d_ptr->textureSize != imageSize; + *flags = 0; + if (image.format() == QImage::Format_RGB32) + *flags |= TextureSwizzle; + + if (imageSize.isEmpty()) { + *textureSize = imageSize; + return 0; + } + + // Must rely on the input only, not d_ptr. + // With the default composeAndFlush() textureSize is &d_ptr->textureSize. + bool resized = *textureSize != imageSize; if (dirtyRegion.isEmpty() && !resized) return d_ptr->textureId; + *textureSize = imageSize; + // Fast path for RGB32 and RGBA8888, convert everything else to RGBA8888. - if (image.format() == QImage::Format_RGB32) { - if (needsSwizzle) - *needsSwizzle = true; - } else { - if (needsSwizzle) - *needsSwizzle = false; - if (image.format() != QImage::Format_RGBA8888) - image = image.convertToFormat(QImage::Format_RGBA8888); - } + if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_RGBA8888) + image = image.convertToFormat(QImage::Format_RGBA8888); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); @@ -412,8 +457,6 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSize.width(), imageSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, const_cast(image.constBits())); - if (textureSize) - *textureSize = imageSize; } else { funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); QRect imageRect = image.rect(); diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index df98ebf51b..eac97e9cf6 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -82,12 +82,14 @@ public: bool isEmpty() const { return count() == 0; } GLuint textureId(int index) const; QRect geometry(int index) const; - QWidget *widget(int index); + QRect clipRect(int index) const; + void *source(int index); Flags flags(int index) const; void lock(bool on); bool isLocked() const; - void appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags = 0); + void appendTexture(void *source, GLuint textureId, const QRect &geometry, + const QRect &clipRect = QRect(), Flags flags = 0); void clear(); Q_SIGNALS: @@ -114,7 +116,12 @@ public: QPlatformTextureList *textures, QOpenGLContext *context, bool translucentBackground); virtual QImage toImage() const; - virtual GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, bool *needsSwizzle) const; + enum TextureFlag { + TextureSwizzle = 0x01, + TextureFlip = 0x02 + }; + Q_DECLARE_FLAGS(TextureFlags, TextureFlag) + virtual GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const; #endif virtual QPlatformGraphicsBuffer *graphicsBuffer() const; @@ -130,6 +137,10 @@ private: QPlatformBackingStorePrivate *d_ptr; }; +#ifndef QT_NO_OPENGL +Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformBackingStore::TextureFlags) +#endif + QT_END_NAMESPACE #endif // QPLATFORMBACKINGSTORE_H diff --git a/src/gui/painting/qpolygon.h b/src/gui/painting/qpolygon.h index ee7d4d31ad..1549ebe2b5 100644 --- a/src/gui/painting/qpolygon.h +++ b/src/gui/painting/qpolygon.h @@ -138,7 +138,7 @@ public: void translate(const QPointF &offset); inline QPolygonF translated(qreal dx, qreal dy) const; - QPolygonF translated(const QPointF &offset) const; + QPolygonF translated(const QPointF &offset) const Q_REQUIRED_RESULT; QPolygon toPolygon() const; @@ -148,9 +148,9 @@ public: bool containsPoint(const QPointF &pt, Qt::FillRule fillRule) const; - QPolygonF united(const QPolygonF &r) const; - QPolygonF intersected(const QPolygonF &r) const; - QPolygonF subtracted(const QPolygonF &r) const; + QPolygonF united(const QPolygonF &r) const Q_REQUIRED_RESULT; + QPolygonF intersected(const QPolygonF &r) const Q_REQUIRED_RESULT; + QPolygonF subtracted(const QPolygonF &r) const Q_REQUIRED_RESULT; }; inline QPolygonF::QPolygonF(int asize) : QVector(asize) {} diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index bab07b5a5d..ab2404e887 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -66,10 +66,10 @@ public: ~QRegion(); QRegion &operator=(const QRegion &); #ifdef Q_COMPILER_RVALUE_REFS - inline QRegion &operator=(QRegion &&other) + inline QRegion &operator=(QRegion &&other) Q_DECL_NOEXCEPT { qSwap(d, other.d); return *this; } #endif - inline void swap(QRegion &other) { qSwap(d, other.d); } + inline void swap(QRegion &other) Q_DECL_NOEXCEPT { qSwap(d, other.d); } bool isEmpty() const; bool isNull() const; diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h index eda65b8e2f..f967c091df 100644 --- a/src/gui/painting/qstroker_p.h +++ b/src/gui/painting/qstroker_p.h @@ -201,7 +201,7 @@ public: QStroker(); ~QStroker(); - void setStrokeWidth(qfixed width) { m_strokeWidth = width; } + void setStrokeWidth(qfixed width) { m_strokeWidth = width; m_curveThreshold = width >= 1 ? 1.0/width : 0.5;} qfixed strokeWidth() const { return m_strokeWidth; } void setCapStyle(Qt::PenCapStyle capStyle) { m_capStyle = joinModeForCap(capStyle); } diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 4b3f0b30dc..fca2b72249 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1102,7 +1102,7 @@ QDataStream & operator>>(QDataStream &s, QTransform &t) #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, const QTransform &m) { - static const char *typeStr[] = + static const char *const typeStr[] = { "TxNone", "TxTranslate", diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index cc78ea7f45..72e4197fc5 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -237,7 +237,7 @@ public: operator QVariant() const; bool isCopyOf(const QFont &) const; #ifdef Q_COMPILER_RVALUE_REFS - inline QFont &operator=(QFont &&other) + inline QFont &operator=(QFont &&other) Q_DECL_NOEXCEPT { qSwap(d, other.d); qSwap(resolve_mask, other.resolve_mask); return *this; } #endif diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 126f0bf3ec..dae4d560a8 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -121,6 +121,8 @@ static int getFontWeight(const QString &weightString) return QFont::DemiBold; return QFont::Bold; } + if (s.contains(QLatin1String("thin"))) + return QFont::Thin; if (s.contains(QLatin1String("light"))) return QFont::Light; if (s.contains(QLatin1String("black"))) @@ -346,7 +348,6 @@ struct QtFontFamily populated(false), fixedPitch(false), name(n), count(0), foundries(0) - , askedForFallback(false) { memset(writingSystems, 0, sizeof(writingSystems)); } @@ -364,8 +365,6 @@ struct QtFontFamily int count; QtFontFoundry **foundries; - QStringList fallbackFamilies; - bool askedForFallback; unsigned char writingSystems[QFontDatabase::WritingSystemsCount]; bool matchesFamilyName(const QString &familyName) const; @@ -630,6 +629,7 @@ static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDe } else { fontDef->pixelSize = desc.size->pixelSize; } + fontDef->pointSize = request.pointSize; fontDef->styleHint = request.styleHint; fontDef->styleStrategy = request.styleStrategy; @@ -758,6 +758,7 @@ QString qt_resolveFontFamilyAlias(const QString &alias) static QStringList fallbackFamilies(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) { + // make sure that the db has all fallback families QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script); QFontDatabasePrivate *db = privateDb(); @@ -883,20 +884,13 @@ QFontEngine *loadEngine(int script, const QFontDef &request, QFontEngine *engine = loadSingleEngine(script, request, family, foundry, style, size); Q_ASSERT(!engine || engine->type() != QFontEngine::Multi); if (engine && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) { - // make sure that the db has all fallback families - if (family && !family->askedForFallback) { - QFont::Style fontStyle = QFont::Style(style->key.style); - QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint); - if (styleHint == QFont::AnyStyle && request.fixedPitch) - styleHint = QFont::TypeWriter; - family->fallbackFamilies = fallbackFamilies(family->name, fontStyle, styleHint, QChar::Script(script)); - - family->askedForFallback = true; - } - QStringList fallbacks = request.fallBackFamilies; - if (family) - fallbacks += family->fallbackFamilies; + + QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint); + if (styleHint == QFont::AnyStyle && request.fixedPitch) + styleHint = QFont::TypeWriter; + + fallbacks += fallbackFamilies(family->name, QFont::Style(style->key.style), styleHint, QChar::Script(script)); QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QChar::Script(script)); @@ -2505,9 +2499,7 @@ bool QFontDatabase::supportsThreadedFontRendering() /*! \internal */ -QFontEngine * -QFontDatabase::findFont(int script, const QFontPrivate *fp, - const QFontDef &request, bool multi) +QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script) { QMutexLocker locker(fontDatabaseMutex()); @@ -2515,6 +2507,11 @@ QFontDatabase::findFont(int script, const QFontPrivate *fp, initializeDb(); QFontEngine *engine; + + // Until we specifically asked not to, try looking for Multi font engine + // first, the last '1' indicates that we want Multi font engine instead + // of single ones + bool multi = !(request.styleStrategy & QFont::NoFontMerging); QFontCache::Key key(request, script, multi ? 1 : 0); engine = QFontCache::instance()->findEngine(key); if (engine) { @@ -2529,6 +2526,7 @@ QFontDatabase::findFont(int script, const QFontPrivate *fp, if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) { engine =new QTestFontEngine(request.pixelSize); engine->fontDef = request; + return engine; } QtFontDesc desc; @@ -2536,24 +2534,14 @@ QFontDatabase::findFont(int script, const QFontPrivate *fp, int index = match(script, request, family_name, foundry_name, &desc, blackListed); if (index >= 0) { engine = loadEngine(script, request, desc.family, desc.foundry, desc.style, desc.size); - if (!engine) + if (engine) + initFontDef(desc, request, &engine->fontDef, multi); + else blackListed.append(index); } else { FM_DEBUG(" NO MATCH FOUND\n"); } - if (engine && engine->type() != QFontEngine::TestFontEngine) { - initFontDef(desc, request, &engine->fontDef, engine->type() == QFontEngine::Multi); - - if (fp) { - QFontDef def = request; - if (def.family.isEmpty()) { - def.family = fp->request.family; - def.family = def.family.left(def.family.indexOf(QLatin1Char(','))); - } - } - } - if (!engine) { if (!request.family.isEmpty()) { QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint); @@ -2583,7 +2571,7 @@ QFontDatabase::findFont(int script, const QFontPrivate *fp, loadDef.family = desc.family->name; engine = loadEngine(script, loadDef, desc.family, desc.foundry, desc.style, desc.size); if (engine) - initFontDef(desc, loadDef, &engine->fontDef, engine->type() == QFontEngine::Multi); + initFontDef(desc, loadDef, &engine->fontDef, multi); else blackListed.append(index); } @@ -2598,12 +2586,6 @@ QFontDatabase::findFont(int script, const QFontPrivate *fp, FM_DEBUG("returning box engine"); } - if (fp && fp->dpi > 0) { - engine->fontDef.pointSize = qreal(double((engine->fontDef.pixelSize * 72) / fp->dpi)); - } else { - engine->fontDef.pointSize = request.pointSize; - } - return engine; } @@ -2671,12 +2653,16 @@ void QFontDatabase::load(const QFontPrivate *d, int script) for (; !fe && it != end; ++it) { req.family = *it; - fe = QFontDatabase::findFont(script, d, req, multi); - if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty()) { - if (fe->ref.load() == 0) - delete fe; - - fe = 0; + fe = QFontDatabase::findFont(req, script); + if (fe) { + if (fe->type() == QFontEngine::Box && !req.family.isEmpty()) { + if (fe->ref.load() == 0) + delete fe; + fe = 0; + } else { + if (d->dpi > 0) + fe->fontDef.pointSize = qreal(double((fe->fontDef.pixelSize * 72) / d->dpi)); + } } // No need to check requested fallback families again diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index 6d738d96be..02bc8e8a08 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -153,7 +153,7 @@ private: static void createDatabase(); static void parseFontName(const QString &name, QString &foundry, QString &family); static QString resolveFontFamilyAlias(const QString &family); - static QFontEngine *findFont(int script, const QFontPrivate *fp, const QFontDef &request, bool multi = false); + static QFontEngine *findFont(const QFontDef &request, int script); static void load(const QFontPrivate *d, int script); friend struct QFontDef; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index b028d868b9..87e6c30afe 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -1641,7 +1641,7 @@ QFontEngine *QFontEngineMulti::loadEngine(int at) request.styleStrategy |= QFont::NoFontMerging; request.family = fallbackFamilyAt(at - 1); - if (QFontEngine *engine = QFontDatabase::findFont(m_script, /*fontprivate = */0, request, /*multi = */false)) { + if (QFontEngine *engine = QFontDatabase::findFont(request, m_script)) { engine->fontDef = request; return engine; } diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 931c71dc63..37be0afccf 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -115,7 +115,7 @@ public: QtFreetypeData::~QtFreetypeData() { - for (QHash::ConstIterator iter = faces.begin(); iter != faces.end(); ++iter) + for (QHash::ConstIterator iter = faces.cbegin(); iter != faces.cend(); ++iter) iter.value()->cleanup(); faces.clear(); FT_Done_FreeType(library); diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp index 7e16983b6c..a678b4c8ea 100644 --- a/src/gui/text/qfontengine_qpf2.cpp +++ b/src/gui/text/qfontengine_qpf2.cpp @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE //#define DEBUG_HEADER //#define DEBUG_FONTENGINE -static QFontEngineQPF2::TagType tagTypes[QFontEngineQPF2::NumTags] = { +static const QFontEngineQPF2::TagType tagTypes[QFontEngineQPF2::NumTags] = { QFontEngineQPF2::StringType, // FontName QFontEngineQPF2::StringType, // FileName QFontEngineQPF2::UInt32Type, // FileIndex diff --git a/src/gui/text/qfontmetrics.h b/src/gui/text/qfontmetrics.h index 12aa2dadb4..65ec219a99 100644 --- a/src/gui/text/qfontmetrics.h +++ b/src/gui/text/qfontmetrics.h @@ -58,11 +58,12 @@ public: QFontMetrics &operator=(const QFontMetrics &); #ifdef Q_COMPILER_RVALUE_REFS - inline QFontMetrics &operator=(QFontMetrics &&other) + inline QFontMetrics &operator=(QFontMetrics &&other) Q_DECL_NOEXCEPT { qSwap(d, other.d); return *this; } #endif - void swap(QFontMetrics &other) { qSwap(d, other.d); } + void swap(QFontMetrics &other) Q_DECL_NOEXCEPT + { qSwap(d, other.d); } int ascent() const; int descent() const; diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index db8a792be7..5864ca0b1a 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -504,8 +504,6 @@ public: void layoutBlock(const QTextBlock &bl, int blockPosition, const QTextBlockFormat &blockFormat, QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat); void layoutFlow(QTextFrame::Iterator it, QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, QFixed width = 0); - void pageBreakInsideTable(QTextTable *table, QTextLayoutStruct *layoutStruct); - void floatMargins(const QFixed &y, const QTextLayoutStruct *layoutStruct, QFixed *left, QFixed *right) const; QFixed findY(QFixed yFrom, const QTextLayoutStruct *layoutStruct, QFixed requiredWidth) const; diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index e5acccb55b..a75a1aae54 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -1264,12 +1264,6 @@ int QTextTable::columns() const return d->nCols; } -#if 0 -void QTextTable::mergeCells(const QTextCursor &selection) -{ -} -#endif - /*! \fn QTextCursor QTextTable::rowStart(const QTextCursor &cursor) const diff --git a/src/gui/text/qzip.cpp b/src/gui/text/qzip.cpp index 9f561dcb02..edd3447357 100644 --- a/src/gui/text/qzip.cpp +++ b/src/gui/text/qzip.cpp @@ -670,7 +670,7 @@ void QZipReaderPrivate::scanFiles() void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const QByteArray &contents/*, QFile::Permissions permissions, QZip::Method m*/) { #ifndef NDEBUG - static const char *entryTypes[] = { + static const char *const entryTypes[] = { "directory", "file ", "symlink " }; diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp index 0114b13209..74c95ecd5e 100644 --- a/src/network/access/qftp.cpp +++ b/src/network/access/qftp.cpp @@ -735,7 +735,10 @@ void QFtpDTP::socketConnectionClosed() clearData(); } - bytesFromSocket = socket->readAll(); + if (socket->isOpen()) + bytesFromSocket = socket->readAll(); + else + bytesFromSocket.clear(); #if defined(QFTPDTP_DEBUG) qDebug("QFtpDTP::connectState(CsClosed)"); #endif diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 647967839a..98247b7df0 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -106,15 +106,19 @@ void QHttpNetworkConnectionChannel::init() socket->setProxy(QNetworkProxy::NoProxy); #endif + // We want all signals (except the interactive ones) be connected as QueuedConnection + // because else we're falling into cases where we recurse back into the socket code + // and mess up the state. Always going to the event loop (and expecting that when reading/writing) + // is safer. QObject::connect(socket, SIGNAL(bytesWritten(qint64)), this, SLOT(_q_bytesWritten(qint64)), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(socket, SIGNAL(connected()), this, SLOT(_q_connected()), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(_q_readyRead()), - Qt::DirectConnection); + Qt::QueuedConnection); // The disconnected() and error() signals may already come // while calling connectToHost(). @@ -143,7 +147,7 @@ void QHttpNetworkConnectionChannel::init() // won't be a sslSocket if encrypt is false QObject::connect(sslSocket, SIGNAL(encrypted()), this, SLOT(_q_encrypted()), - Qt::DirectConnection); + Qt::QueuedConnection); QObject::connect(sslSocket, SIGNAL(sslErrors(QList)), this, SLOT(_q_sslErrors(QList)), Qt::DirectConnection); @@ -152,7 +156,7 @@ void QHttpNetworkConnectionChannel::init() Qt::DirectConnection); QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)), - Qt::DirectConnection); + Qt::QueuedConnection); if (ignoreAllSslErrors) sslSocket->ignoreSslErrors(); @@ -189,8 +193,11 @@ void QHttpNetworkConnectionChannel::close() // pendingEncrypt must only be true in between connected and encrypted states pendingEncrypt = false; - if (socket) + if (socket) { + // socket can be 0 since the host lookup is done from qhttpnetworkconnection.cpp while + // there is no socket yet. socket->close(); + } } @@ -356,6 +363,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection() } return false; } + + // This code path for ConnectedState + if (pendingEncrypt) { + // Let's only be really connected when we have received the encrypted() signal. Else the state machine seems to mess up + // and corrupt the things sent to the server. + return false; + } + return true; } @@ -676,6 +691,12 @@ bool QHttpNetworkConnectionChannel::isSocketReading() const void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes) { Q_UNUSED(bytes); + if (ssl) { + // In the SSL case we want to send data from encryptedBytesWritten signal since that one + // is the one going down to the actual network, not only into some SSL buffer. + return; + } + // bytes have been written to the socket. write even more of them :) if (isSocketWriting()) sendRequest(); @@ -751,7 +772,7 @@ void QHttpNetworkConnectionChannel::_q_connected() // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again! //channels[i].reconnectAttempts = 2; - if (pendingEncrypt) { + if (ssl || pendingEncrypt) { // FIXME: Didn't work properly with pendingEncrypt only, we should refactor this into an EncrypingState #ifndef QT_NO_SSL if (connection->sslContext().isNull()) { // this socket is making the 1st handshake for this connection, diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 6872fcb691..16d6c3b40f 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -83,6 +83,8 @@ typedef QPair HttpMessagePair; class QHttpNetworkConnectionChannel : public QObject { Q_OBJECT public: + // TODO: Refactor this to add an EncryptingState (and remove pendingEncrypt). + // Also add an Unconnected state so IdleState does not have double meaning. enum ChannelState { IdleState = 0, // ready to send request ConnectingState = 1, // connecting to host diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp index eac261bc80..55187755bf 100644 --- a/src/network/access/qhttpprotocolhandler.cpp +++ b/src/network/access/qhttpprotocolhandler.cpp @@ -368,6 +368,13 @@ bool QHttpProtocolHandler::sendRequest() // nothing to read currently, break the loop break; } else { + if (m_channel->written != uploadByteDevice->pos()) { + // Sanity check. This was useful in tracking down an upload corruption. + qWarning() << "QHttpProtocolHandler: Internal error in sendRequest. Expected to write at position" << m_channel->written << "but read device is at" << uploadByteDevice->pos(); + Q_ASSERT(m_channel->written == uploadByteDevice->pos()); + m_connection->d_func()->emitReplyError(m_socket, m_reply, QNetworkReply::ProtocolFailure); + return false; + } qint64 currentWriteSize = m_socket->write(readPointer, currentReadSize); if (currentWriteSize == -1 || currentWriteSize != currentReadSize) { // socket broke down diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 4889bcd1f1..784e9c14b8 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -191,6 +191,7 @@ protected: QByteArray m_dataArray; bool m_atEnd; qint64 m_size; + qint64 m_pos; // to match calls of haveDataSlot with the expected position public: QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s) : QNonContiguousByteDevice(), @@ -198,7 +199,8 @@ public: m_amount(0), m_data(0), m_atEnd(aE), - m_size(s) + m_size(s), + m_pos(0) { } @@ -206,6 +208,11 @@ public: { } + qint64 pos() Q_DECL_OVERRIDE + { + return m_pos; + } + const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE { if (m_amount > 0) { @@ -233,11 +240,10 @@ public: m_amount -= a; m_data += a; + m_pos += a; - // To main thread to inform about our state - emit processedData(a); - - // FIXME possible optimization, already ask user thread for some data + // To main thread to inform about our state. The m_pos will be sent as a sanity check. + emit processedData(m_pos, a); return true; } @@ -254,10 +260,21 @@ public: { m_amount = 0; m_data = 0; + m_dataArray.clear(); + + if (wantDataPending) { + // had requested the user thread to send some data (only 1 in-flight at any moment) + wantDataPending = false; + } // Communicate as BlockingQueuedConnection bool b = false; emit resetData(&b); + if (b) { + // the reset succeeded, we're at pos 0 again + m_pos = 0; + // the HTTP code will anyway abort the request if !b. + } return b; } @@ -268,8 +285,13 @@ public: public slots: // From user thread: - void haveDataSlot(QByteArray dataArray, bool dataAtEnd, qint64 dataSize) + void haveDataSlot(qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize) { + if (pos != m_pos) { + // Sometimes when re-sending a request in the qhttpnetwork* layer there is a pending haveData from the + // user thread on the way to us. We need to ignore it since it is the data for the wrong(later) chunk. + return; + } wantDataPending = false; m_dataArray = dataArray; @@ -289,7 +311,7 @@ signals: // to main thread: void wantData(qint64); - void processedData(qint64); + void processedData(qint64 pos, qint64 amount); void resetData(bool *b); }; diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index d4c7e121f0..e878feb2bf 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -985,6 +985,27 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess } } +/*! + \internal + + Returns the network session currently in use. + This can be changed at any time, ownership remains with the QNetworkAccessManager +*/ +const QWeakPointer QNetworkAccessManagerPrivate::getNetworkSession(const QNetworkAccessManager *q) +{ + return q->d_func()->networkSessionWeakRef; +} + +QSharedPointer QNetworkAccessManagerPrivate::getNetworkSession() const +{ + if (networkSessionStrongRef) + return networkSessionStrongRef; + return networkSessionWeakRef.toStrongRef(); +} + +#endif // QT_NO_BEARERMANAGEMENT + + #ifndef QT_NO_SSL /*! \since 5.2 @@ -1045,26 +1066,6 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port) get(request); } -/*! - \internal - - Returns the network session currently in use. - This can be changed at any time, ownership remains with the QNetworkAccessManager -*/ -const QWeakPointer QNetworkAccessManagerPrivate::getNetworkSession(const QNetworkAccessManager *q) -{ - return q->d_func()->networkSessionWeakRef; -} - -QSharedPointer QNetworkAccessManagerPrivate::getNetworkSession() const -{ - if (networkSessionStrongRef) - return networkSessionStrongRef; - return networkSessionWeakRef.toStrongRef(); -} - -#endif // QT_NO_BEARERMANAGEMENT - /*! \since 4.7 diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index 2b11e5f993..8a24fc55fd 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -499,7 +499,7 @@ static const char zones[] = "eet\0" // 2 "jst\0" // 9 "\0"; -static int zoneOffsets[] = {-8, -8, -7, -7, -6, -6, -5, -5, -4, -3, 0, 0, 0, 1, 2, 9 }; +static const int zoneOffsets[] = {-8, -8, -7, -7, -6, -6, -5, -5, -4, -3, 0, 0, 0, 1, 2, 9 }; static const char months[] = "jan\0" diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 47621f41d8..c08648c47b 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -425,6 +425,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate() , synchronous(false) , state(Idle) , statusCode(0) + , uploadByteDevicePosition(false) , uploadDeviceChoking(false) , outgoingData(0) , bytesUploaded(-1) @@ -874,9 +875,9 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq q, SLOT(uploadByteDeviceReadyReadSlot()), Qt::QueuedConnection); - // From main thread to user thread: - QObject::connect(q, SIGNAL(haveUploadData(QByteArray,bool,qint64)), - forwardUploadDevice, SLOT(haveDataSlot(QByteArray,bool,qint64)), Qt::QueuedConnection); + // From user thread to http thread: + QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,bool,qint64)), + forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,bool,qint64)), Qt::QueuedConnection); QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()), forwardUploadDevice, SIGNAL(readyRead()), Qt::QueuedConnection); @@ -884,8 +885,8 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq // From http thread to user thread: QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)), q, SLOT(wantUploadDataSlot(qint64))); - QObject::connect(forwardUploadDevice, SIGNAL(processedData(qint64)), - q, SLOT(sentUploadDataSlot(qint64))); + QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64, qint64)), + q, SLOT(sentUploadDataSlot(qint64,qint64))); QObject::connect(forwardUploadDevice, SIGNAL(resetData(bool*)), q, SLOT(resetUploadDataSlot(bool*)), Qt::BlockingQueuedConnection); // this is the only one with BlockingQueued! @@ -1365,12 +1366,22 @@ void QNetworkReplyHttpImplPrivate::replyPreSharedKeyAuthenticationRequiredSlot(Q void QNetworkReplyHttpImplPrivate::resetUploadDataSlot(bool *r) { *r = uploadByteDevice->reset(); + if (*r) { + // reset our own position which is used for the inter-thread communication + uploadByteDevicePosition = 0; + } } // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread -void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 amount) +void QNetworkReplyHttpImplPrivate::sentUploadDataSlot(qint64 pos, qint64 amount) { + if (uploadByteDevicePosition + amount != pos) { + // Sanity check, should not happen. + error(QNetworkReply::UnknownNetworkError, QString()); + return; + } uploadByteDevice->advanceReadPointer(amount); + uploadByteDevicePosition += amount; } // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread @@ -1395,7 +1406,7 @@ void QNetworkReplyHttpImplPrivate::wantUploadDataSlot(qint64 maxSize) QByteArray dataArray(data, currentUploadDataLength); // Communicate back to HTTP thread - emit q->haveUploadData(dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); + emit q->haveUploadData(uploadByteDevicePosition, dataArray, uploadByteDevice->atEnd(), uploadByteDevice->size()); } void QNetworkReplyHttpImplPrivate::uploadByteDeviceReadyReadSlot() diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 08f3fcf342..fff88f8f2d 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -122,7 +122,7 @@ public: Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r)) Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64)) - Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64)) + Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64,qint64)) Q_PRIVATE_SLOT(d_func(), void uploadByteDeviceReadyReadSlot()) Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64)) Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose()) @@ -146,7 +146,7 @@ signals: void startHttpRequestSynchronously(); - void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize); + void haveUploadData(const qint64 pos, QByteArray dataArray, bool dataAtEnd, qint64 dataSize); }; class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate @@ -197,6 +197,7 @@ public: // upload QNonContiguousByteDevice* createUploadByteDevice(); QSharedPointer uploadByteDevice; + qint64 uploadByteDevicePosition; bool uploadDeviceChoking; // if we couldn't readPointer() any data at the moment QIODevice *outgoingData; QSharedPointer outgoingDataBuffer; @@ -288,7 +289,7 @@ public: // From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread: void resetUploadDataSlot(bool *r); void wantUploadDataSlot(qint64); - void sentUploadDataSlot(qint64); + void sentUploadDataSlot(qint64, qint64); // From user's QNonContiguousByteDevice void uploadByteDeviceReadyReadSlot(); diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp index 33d42370b7..c1e837de7b 100644 --- a/src/network/bearer/qnetworkconfigmanager_p.cpp +++ b/src/network/bearer/qnetworkconfigmanager_p.cpp @@ -75,6 +75,7 @@ QNetworkConfigurationManagerPrivate::~QNetworkConfigurationManagerPrivate() QMutexLocker locker(&mutex); qDeleteAll(sessionEngines); + sessionEngines.clear(); if (bearerThread) bearerThread->quit(); } diff --git a/src/network/doc/src/ssl.qdoc b/src/network/doc/src/ssl.qdoc index 5a994a114c..45dffc95a3 100644 --- a/src/network/doc/src/ssl.qdoc +++ b/src/network/doc/src/ssl.qdoc @@ -36,6 +36,8 @@ the Secure Sockets Layer (SSL) protocol, using the OpenSSL Toolkit (\l{http://www.openssl.org/}) to perform encryption and protocol handling. + \annotatedlist ssl + See the \l {openssl-v1later}{OpenSSL Compatibility} page for information about the versions of OpenSSL that are known to work with Qt. diff --git a/src/network/kernel/qhostinfo_winrt.cpp b/src/network/kernel/qhostinfo_winrt.cpp index 0e606c2070..1a97fe0e40 100644 --- a/src/network/kernel/qhostinfo_winrt.cpp +++ b/src/network/kernel/qhostinfo_winrt.cpp @@ -35,7 +35,6 @@ #include -#include #include #include #include diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h index 361fcf7ca2..42920c96f2 100644 --- a/src/network/socket/qnativesocketengine_winrt_p.h +++ b/src/network/socket/qnativesocketengine_winrt_p.h @@ -46,6 +46,7 @@ // #include #include +#include #include "QtNetwork/qhostaddress.h" #include "private/qabstractsocketengine_p.h" #include diff --git a/src/network/ssl/qasn1element.cpp b/src/network/ssl/qasn1element.cpp index 95c360e7af..82807aec6e 100644 --- a/src/network/ssl/qasn1element.cpp +++ b/src/network/ssl/qasn1element.cpp @@ -46,32 +46,32 @@ static OidNameMap createOidMap() { OidNameMap oids; // used by unit tests - oids.insert(oids.end(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink")); - oids.insert(oids.end(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress")); - oids.insert(oids.end(), QByteArrayLiteral("1.3.6.1.5.5.7.1.1"), QByteArrayLiteral("authorityInfoAccess")); - oids.insert(oids.end(), QByteArrayLiteral("1.3.6.1.5.5.7.48.1"), QByteArrayLiteral("OCSP")); - oids.insert(oids.end(), QByteArrayLiteral("1.3.6.1.5.5.7.48.2"), QByteArrayLiteral("caIssuers")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.29.14"), QByteArrayLiteral("subjectKeyIdentifier")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.29.15"), QByteArrayLiteral("keyUsage")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.29.17"), QByteArrayLiteral("subjectAltName")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.29.19"), QByteArrayLiteral("basicConstraints")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.29.35"), QByteArrayLiteral("authorityKeyIdentifier")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST")); - oids.insert(oids.end(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street")); + oids.insert(oids.cend(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink")); + oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress")); + oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.1.1"), QByteArrayLiteral("authorityInfoAccess")); + oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.1"), QByteArrayLiteral("OCSP")); + oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.2"), QByteArrayLiteral("caIssuers")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.14"), QByteArrayLiteral("subjectKeyIdentifier")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.15"), QByteArrayLiteral("keyUsage")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.17"), QByteArrayLiteral("subjectAltName")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.19"), QByteArrayLiteral("basicConstraints")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.35"), QByteArrayLiteral("authorityKeyIdentifier")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST")); + oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street")); return oids; } Q_GLOBAL_STATIC_WITH_ARGS(OidNameMap, oidNameMap, (createOidMap())) diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index 1aac152ca3..6f91ccdb4d 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -594,7 +594,7 @@ bool QSslCertificate::importPkcs12(QIODevice *device, // These certificates are known to be fraudulent and were created during the comodo // compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html -static const char *certificate_blacklist[] = { +static const char *const certificate_blacklist[] = { "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e", "mail.google.com", // Comodo "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06", "www.google.com", // Comodo "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3", "login.yahoo.com", // Comodo diff --git a/src/network/ssl/qsslellipticcurve_dummy.cpp b/src/network/ssl/qsslellipticcurve_dummy.cpp index d05c920a49..16b7a3cd00 100644 --- a/src/network/ssl/qsslellipticcurve_dummy.cpp +++ b/src/network/ssl/qsslellipticcurve_dummy.cpp @@ -57,7 +57,7 @@ QSslEllipticCurve QSslEllipticCurve::fromLongName(const QString &name) return QSslEllipticCurve(); } -bool QSslEllipticCurve::isTlsNamedCurve() const +bool QSslEllipticCurve::isTlsNamedCurve() const Q_DECL_NOTHROW { return false; } diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 0bb153516c..436588afc5 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -618,7 +618,10 @@ long QSslSocketPrivate::sslLibraryBuildVersionNumber() QString QSslSocketPrivate::sslLibraryBuildVersionString() { - return QLatin1String(OPENSSL_VERSION_TEXT); + // Using QStringLiteral to store the version string as unicode and + // avoid false positives from Google searching the playstore for old + // SSL versions. See QTBUG-46265 + return QStringLiteral(OPENSSL_VERSION_TEXT); } /*! diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 637bd1c560..8e5d93dce2 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -508,7 +508,7 @@ GLuint QGLEngineShaderManager::getUniformLocation(Uniform id) if (uniformLocations.isEmpty()) uniformLocations.fill(GLuint(-1), NumUniforms); - static const char *uniformNames[] = { + static const char *const uniformNames[] = { "imageTexture", "patternColor", "globalOpacity", diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 637c375311..9a1ae6e008 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -304,19 +304,23 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed sub for (int x = 0; x < maskWidth; ++x) src[x] = -src[x]; // convert 0 and 1 into 0 and 255 } - } else if (mask.format() == QImage::Format_RGB32) { + } else if (mask.depth() == 32) { // Make the alpha component equal to the average of the RGB values. // This is needed when drawing sub-pixel antialiased text on translucent targets. for (int y = 0; y < maskHeight; ++y) { quint32 *src = (quint32 *) mask.scanLine(y); for (int x = 0; x < maskWidth; ++x) { - uchar r = src[x] >> 16; - uchar g = src[x] >> 8; - uchar b = src[x]; - quint32 avg = (quint32(r) + quint32(g) + quint32(b) + 1) / 3; // "+1" for rounding. + int r = qRed(src[x]); + int g = qGreen(src[x]); + int b = qBlue(src[x]); + int avg; + if (mask.format() == QImage::Format_RGB32) + avg = (r + g + b + 1) / 3; // "+1" for rounding. + else // Format_ARGB_Premultiplied + avg = qAlpha(src[x]); 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); + src[x] = (avg << 24) | (r << 0) | (g << 8) | (b << 16); } else { src[x] = (src[x] & 0x00ffffff) | (avg << 24); } @@ -325,7 +329,7 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed sub } funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); - if (mask.format() == QImage::Format_RGB32) { + if (mask.depth() == 32) { GLenum format = GL_RGBA; #if !defined(QT_OPENGL_ES_2) if (!ctx->contextHandle()->isOpenGLES()) diff --git a/src/platformheaders/xcbfunctions/qxcbwindowfunctions.qdoc b/src/platformheaders/xcbfunctions/qxcbwindowfunctions.qdoc index 771b56e060..a02f93968d 100644 --- a/src/platformheaders/xcbfunctions/qxcbwindowfunctions.qdoc +++ b/src/platformheaders/xcbfunctions/qxcbwindowfunctions.qdoc @@ -32,7 +32,7 @@ \brief The QXcbWindowFunctions class is an inline class containing miscellaneous functionality for xcb window specific functionality. - A commen usage pattern is as follows: + A common usage pattern is as follows: \snippet qxcbwindowfunctions/main.cpp 0 \note There is no binary compatibility guarantee for this class, diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp b/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp index 93c822cefb..a64e107e71 100644 --- a/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu.cpp @@ -75,6 +75,9 @@ void QDBusPlatformMenuItem::setIcon(const QIcon &icon) m_icon = icon; } +/*! + Set a submenu under this menu item. +*/ void QDBusPlatformMenuItem::setMenu(QPlatformMenu *menu) { m_subMenu = static_cast(menu); @@ -242,8 +245,12 @@ const QList QDBusPlatformMenu::items() const QPlatformMenuItem *QDBusPlatformMenu::createMenuItem() const { QDBusPlatformMenuItem *ret = new QDBusPlatformMenuItem(); - ret->setMenu(const_cast(this)); return ret; } +QPlatformMenu *QDBusPlatformMenu::createSubMenu() const +{ + return new QDBusPlatformMenu; +} + QT_END_NAMESPACE diff --git a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h index 2519533e32..16bb4f195c 100644 --- a/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h +++ b/src/platformsupport/dbusmenu/qdbusplatformmenu_p.h @@ -124,7 +124,7 @@ public: quintptr tag()const Q_DECL_OVERRIDE { return m_tag; } void setTag(quintptr tag) Q_DECL_OVERRIDE; - const QString text() { return m_text; } + const QString text() const { return m_text; } void setText(const QString &text) Q_DECL_OVERRIDE; void setIcon(const QIcon &icon) Q_DECL_OVERRIDE; void setEnabled(bool enabled) Q_DECL_OVERRIDE; @@ -150,6 +150,7 @@ public: const QList items() const; QPlatformMenuItem *createMenuItem() const Q_DECL_OVERRIDE; + QPlatformMenu *createSubMenu() const Q_DECL_OVERRIDE; bool operator==(const QDBusPlatformMenu& other) { return m_tag == other.m_tag; } @@ -175,6 +176,7 @@ private: uint m_revision; QHash m_itemsByTag; QList m_items; + QDBusPlatformMenuItem *m_containingMenuItem; static QList m_topLevelMenus; }; diff --git a/src/platformsupport/platformcompositor/qopenglcompositor.cpp b/src/platformsupport/platformcompositor/qopenglcompositor.cpp index 3fd6c999a2..2e386532e2 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositor.cpp +++ b/src/platformsupport/platformcompositor/qopenglcompositor.cpp @@ -169,6 +169,29 @@ struct BlendStateBinder bool m_blend; }; +static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) +{ + return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1, + topLeftRect.width(), topLeftRect.height()); +} + +static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &targetWindowRect, QOpenGLTextureBlitter *blitter) +{ + const QRect rectInWindow = textures->geometry(idx); + QRect clipRect = textures->clipRect(idx); + if (clipRect.isEmpty()) + clipRect = QRect(QPoint(0, 0), rectInWindow.size()); + + const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft()); + const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height()); + + const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(clippedRectInWindow, targetWindowRect); + const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect, rectInWindow.size(), + QOpenGLTextureBlitter::OriginBottomLeft); + + blitter->blit(textures->textureId(idx), target, source); +} + void QOpenGLCompositor::render(QOpenGLCompositorWindow *window) { const QPlatformTextureList *textures = window->textures(); @@ -181,7 +204,6 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window) for (int i = 0; i < textures->count(); ++i) { uint textureId = textures->textureId(i); - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); const float opacity = window->sourceWindow()->opacity(); if (opacity != currentOpacity) { currentOpacity = opacity; @@ -191,24 +213,25 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window) if (textures->count() > 1 && i == textures->count() - 1) { // Backingstore for a widget with QOpenGLWidget subwidgets blend.set(true); + const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); } else if (textures->count() == 1) { // A regular QWidget window const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0; blend.set(translucent); + const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); } else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { // Texture from an FBO belonging to a QOpenGLWidget blend.set(false); - m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft); + clippedBlit(textures, i, targetWindowRect, &m_blitter); } } for (int i = 0; i < textures->count(); ++i) { if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect); blend.set(true); - m_blitter.blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); + clippedBlit(textures, i, targetWindowRect, &m_blitter); } } diff --git a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp index 3caec468a6..8ce1ed2d2b 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp +++ b/src/platformsupport/platformcompositor/qopenglcompositorbackingstore.cpp @@ -175,7 +175,8 @@ void QOpenGLCompositorBackingStore::composeAndFlush(QWindow *window, const QRegi m_textures->clear(); for (int i = 0; i < textures->count(); ++i) - m_textures->appendTexture(textures->widget(i), textures->textureId(i), textures->geometry(i), textures->flags(i)); + m_textures->appendTexture(textures->source(i), textures->textureId(i), textures->geometry(i), + textures->clipRect(i), textures->flags(i)); updateTexture(); m_textures->appendTexture(Q_NULLPTR, m_bsTexture, window->geometry()); diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm index db02cfd19d..6d16b59d35 100644 --- a/src/plugins/bearer/corewlan/qcorewlanengine.mm +++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm @@ -44,6 +44,7 @@ #include #include +#ifndef QT_NO_BEARERMANAGEMENT extern "C" { // Otherwise it won't find CWKeychain* symbols at link time #import @@ -84,8 +85,11 @@ extern "C" { // Otherwise it won't find CWKeychain* symbols at link time return self; } +static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; + -(void)dealloc { + listener = nil; [super dealloc]; } @@ -116,7 +120,6 @@ extern "C" { // Otherwise it won't find CWKeychain* symbols at link time } @end -static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0; QT_BEGIN_NAMESPACE @@ -878,3 +881,5 @@ quint64 QCoreWlanEngine::getBytes(const QString &interfaceName, bool b) } QT_END_NAMESPACE + +#endif diff --git a/src/plugins/generic/evdevkeyboard/main.cpp b/src/plugins/generic/evdevkeyboard/main.cpp index ceb8f4f792..444c9f1559 100644 --- a/src/plugins/generic/evdevkeyboard/main.cpp +++ b/src/plugins/generic/evdevkeyboard/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QEvdevKeyboardPlugin : public QGenericPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "evdevkeyboard.json") + Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "evdevkeyboard.json") public: QEvdevKeyboardPlugin(); diff --git a/src/plugins/generic/evdevmouse/main.cpp b/src/plugins/generic/evdevmouse/main.cpp index 7e9932ceb9..f39f92cfd2 100644 --- a/src/plugins/generic/evdevmouse/main.cpp +++ b/src/plugins/generic/evdevmouse/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QEvdevMousePlugin : public QGenericPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "evdevmouse.json") + Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "evdevmouse.json") public: QEvdevMousePlugin(); diff --git a/src/plugins/generic/evdevtablet/main.cpp b/src/plugins/generic/evdevtablet/main.cpp index 7d62e1a2bc..62524e8f33 100644 --- a/src/plugins/generic/evdevtablet/main.cpp +++ b/src/plugins/generic/evdevtablet/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QEvdevTabletPlugin : public QGenericPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "evdevtablet.json") + Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "evdevtablet.json") public: QEvdevTabletPlugin(); diff --git a/src/plugins/generic/evdevtouch/main.cpp b/src/plugins/generic/evdevtouch/main.cpp index ef6774b0a0..bb78dd6e84 100644 --- a/src/plugins/generic/evdevtouch/main.cpp +++ b/src/plugins/generic/evdevtouch/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QEvdevTouchScreenPlugin : public QGenericPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "evdevtouch.json") + Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "evdevtouch.json") public: QEvdevTouchScreenPlugin(); diff --git a/src/plugins/generic/libinput/main.cpp b/src/plugins/generic/libinput/main.cpp index 2adc0c747b..9459ca3621 100644 --- a/src/plugins/generic/libinput/main.cpp +++ b/src/plugins/generic/libinput/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QLibInputPlugin : public QGenericPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "libinput.json") + Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "libinput.json") public: QObject *create(const QString &key, const QString &specification); diff --git a/src/plugins/generic/tslib/main.cpp b/src/plugins/generic/tslib/main.cpp index 36f1ac7c3c..9459e85544 100644 --- a/src/plugins/generic/tslib/main.cpp +++ b/src/plugins/generic/tslib/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QTsLibPlugin : public QGenericPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "tslib.json") + Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "tslib.json") public: QObject* create(const QString &key, const QString &specification); diff --git a/src/plugins/generic/tuiotouch/main.cpp b/src/plugins/generic/tuiotouch/main.cpp index e1d08f0e26..35e74e32bd 100644 --- a/src/plugins/generic/tuiotouch/main.cpp +++ b/src/plugins/generic/tuiotouch/main.cpp @@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE class QTuioTouchPlugin : public QGenericPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QGenericPluginFactoryInterface" FILE "tuiotouch.json") + Q_PLUGIN_METADATA(IID QGenericPluginFactoryInterface_iid FILE "tuiotouch.json") public: QTuioTouchPlugin(); diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp index 5ab0dd8f04..96f6424ba2 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp @@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE class QComposePlatformInputContextPlugin : public QPlatformInputContextPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface" FILE "compose.json") + Q_PLUGIN_METADATA(IID QPlatformInputContextFactoryInterface_iid FILE "compose.json") public: QComposeInputContext *create(const QString &, const QStringList &) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforminputcontexts/ibus/main.cpp b/src/plugins/platforminputcontexts/ibus/main.cpp index b621bec1ee..1b1a3be2c4 100644 --- a/src/plugins/platforminputcontexts/ibus/main.cpp +++ b/src/plugins/platforminputcontexts/ibus/main.cpp @@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE class QIbusPlatformInputContextPlugin : public QPlatformInputContextPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformInputContextFactoryInterface" FILE "ibus.json") + Q_PLUGIN_METADATA(IID QPlatformInputContextFactoryInterface_iid FILE "ibus.json") public: QIBusPlatformInputContext *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/android/androidplatformplugin.cpp b/src/plugins/platforms/android/androidplatformplugin.cpp index ea7a3c397a..245691e79f 100644 --- a/src/plugins/platforms/android/androidplatformplugin.cpp +++ b/src/plugins/platforms/android/androidplatformplugin.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QAndroidPlatformIntegrationPlugin: public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "android.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "android.json") public: QPlatformIntegration *create(const QString &key, const QStringList ¶mList); }; diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 88bc4a653a..5c8406ca03 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -176,6 +176,8 @@ static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags) #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ GETSEL" << text; #endif + if (text.isEmpty()) + return 0; return env->NewString(reinterpret_cast(text.constData()), jsize(text.length())); } diff --git a/src/plugins/platforms/cocoa/main.mm b/src/plugins/platforms/cocoa/main.mm index ed139b98b2..e6c1ed79b2 100644 --- a/src/plugins/platforms/cocoa/main.mm +++ b/src/plugins/platforms/cocoa/main.mm @@ -43,7 +43,7 @@ QT_BEGIN_NAMESPACE class QCocoaIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "cocoa.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "cocoa.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h index 48d7efe174..36943a563e 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h @@ -51,6 +51,7 @@ public: virtual ~QCocoaFileDialogHelper(); void exec(); + void execModalForWindow(QWindow *parent); bool defaultNameFilterDisables() const; diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 93ee4e8624..fad3f28053 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -253,17 +253,22 @@ static QString strippedText(QString s) || [self panel:nil shouldShowFilename:filepath]; [self updateProperties]; - QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder(); [mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]]; [mSavePanel setNameFieldStringValue:selectable ? QCFString::toNSString(info.fileName()) : @""]; NSWindow *nsparent = static_cast(qGuiApp->platformNativeInterface()->nativeResourceForWindow("nswindow", parent)); + qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); + QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder(); + [mSavePanel beginSheetModalForWindow:nsparent completionHandler:^(NSInteger result){ - mReturnCode = result; - if (mHelper) - mHelper->QNSOpenSavePanelDelegate_panelClosed(result == NSOKButton); + [[NSApplication sharedApplication] stopModalWithCode:result]; }]; + + mReturnCode = [[NSApplication sharedApplication] runModalForWindow:nsparent]; + QAbstractEventDispatcher::instance()->interrupt(); + if (mHelper) + mHelper->QNSOpenSavePanelDelegate_panelClosed(mReturnCode == NSOKButton); } - (BOOL)isHiddenFile:(NSString *)filename isDir:(BOOL)isDir @@ -705,14 +710,15 @@ void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate() bool QCocoaFileDialogHelper::showCocoaFilePanel(Qt::WindowModality windowModality, QWindow *parent) { + Q_UNUSED(parent) + createNSOpenSavePanelDelegate(); if (!mDelegate) return false; if (windowModality == Qt::NonModal) [mDelegate showModelessPanel]; - else if (windowModality == Qt::WindowModal && parent) - [mDelegate showWindowModalSheet:parent]; - // no need to show a Qt::ApplicationModal dialog here, since it will be done in _q_platformRunNativeAppModalPanel() + // no need to show a Qt::ApplicationModal dialog here, since it will be done in exec; + // Qt::WindowModal will be done in execModalForWindow. return true; } @@ -744,6 +750,14 @@ void QCocoaFileDialogHelper::exec() } +void QCocoaFileDialogHelper::execModalForWindow(QWindow *parent) +{ + if (!parent) + return exec(); + + [mDelegate showWindowModalSheet:parent]; +} + bool QCocoaFileDialogHelper::defaultNameFilterDisables() const { return true; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index b9ffecd3b0..eb231f064e 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -80,7 +80,7 @@ QT_END_NAMESPACE } - (id) initWithMenu:(QCocoaMenu*) m; -- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier; +- (NSMenuItem *)findItem:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier; @end @@ -151,11 +151,20 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate); // Change the private unicode keys to the ones used in setting the "Key Equivalents" NSString *characters = qt_mac_removePrivateUnicode([event characters]); - if ([self hasShortcut:menu - forKey:characters - // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ... - forModifiers:([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask)) - ]) { + // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ... + const NSUInteger mask = NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask; + if (NSMenuItem *menuItem = [self findItem:menu forKey:characters forModifiers:([event modifierFlags] & mask)]) { + if (!menuItem.target) { + // This item was modified by QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder + // and it looks like we're running a modal session for NSOpenPanel/NSSavePanel. + // QCocoaFileDialogHelper is actually the only place we use this and we run NSOpenPanel modal + // (modal sheet, window modal, application modal). + // Whatever the current first responder is, let's give it a chance + // and do not touch the Qt's focusObject (which is different from some native view + // having a focus inside NSSave/OpenPanel. + return YES; + } + QObject *object = qApp->focusObject(); if (object) { QChar ch; @@ -193,22 +202,23 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate); return NO; } -- (BOOL)hasShortcut:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier +- (NSMenuItem *)findItem:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier { for (NSMenuItem *item in [menu itemArray]) { if (![item isEnabled] || [item isHidden] || [item isSeparatorItem]) continue; - if ([item hasSubmenu] - && [self hasShortcut:[item submenu] forKey:key forModifiers:modifier]) - return YES; + if ([item hasSubmenu]) { + if (NSMenuItem *nested = [self findItem:[item submenu] forKey:key forModifiers:modifier]) + return nested; + } NSString *menuKey = [item keyEquivalent]; if (menuKey && NSOrderedSame == [menuKey compare:key] && modifier == [item keyEquivalentModifierMask]) - return YES; + return item; } - return NO; + return nil; } @end diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.h b/src/plugins/platforms/cocoa/qcocoaprintdevice.h index 2133900048..3ac112781f 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.h +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.h @@ -60,13 +60,8 @@ class QCocoaPrintDevice : public QPlatformPrintDevice public: QCocoaPrintDevice(); explicit QCocoaPrintDevice(const QString &id); - QCocoaPrintDevice(const QCocoaPrintDevice &other); virtual ~QCocoaPrintDevice(); - QCocoaPrintDevice *clone(); - - bool operator==(const QCocoaPrintDevice &other) const; - bool isValid() const Q_DECL_OVERRIDE; bool isDefault() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm index b92ec31a11..4d319e149b 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm @@ -96,24 +96,6 @@ QCocoaPrintDevice::QCocoaPrintDevice(const QString &id) } } -QCocoaPrintDevice::QCocoaPrintDevice(const QCocoaPrintDevice &other) - : QPlatformPrintDevice(other), - m_printer(0), - m_session(0), - m_ppd(0) -{ - m_printer = other.m_printer; - PMRetain(m_printer); - m_session = other.m_session; - PMRetain(m_session); - m_macPapers = other.m_macPapers; - foreach (PMPaper paper, m_macPapers.values()) - PMRetain(paper); - openPpdFile(); - m_customMargins = other.m_customMargins; - m_printableMargins = other.m_printableMargins; -} - QCocoaPrintDevice::~QCocoaPrintDevice() { if (m_ppd) @@ -127,16 +109,6 @@ QCocoaPrintDevice::~QCocoaPrintDevice() PMRelease(m_printer); } -QCocoaPrintDevice *QCocoaPrintDevice::clone() -{ - return new QCocoaPrintDevice(*this); -} - -bool QCocoaPrintDevice::operator==(const QCocoaPrintDevice &other) const -{ - return (m_id == other.m_id); -} - bool QCocoaPrintDevice::isValid() const { return m_printer ? true : false; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 8af0a71bc1..fdc8b2d9ad 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -415,7 +415,7 @@ QCocoaWindow::~QCocoaWindow() if (m_isNSWindowChild) { if (m_parentCocoaWindow) m_parentCocoaWindow->removeChildWindow(this); - } else if (parent()) { + } else if ([m_contentView superview]) { [m_contentView removeFromSuperview]; } @@ -435,7 +435,9 @@ QCocoaWindow::~QCocoaWindow() // While it is unlikely that this window will be in the popup stack // during deletetion we clear any pointers here to make sure. - QCocoaIntegration::instance()->popupWindowStack()->removeAll(this); + if (QCocoaIntegration::instance()) { + QCocoaIntegration::instance()->popupWindowStack()->removeAll(this); + } foreach (QCocoaWindow *child, m_childWindows) { [m_nsWindow removeChildWindow:child->m_nsWindow]; @@ -449,7 +451,13 @@ QCocoaWindow::~QCocoaWindow() QSurfaceFormat QCocoaWindow::format() const { - return window()->requestedFormat(); + QSurfaceFormat format = window()->requestedFormat(); + + // Upgrade the default surface format to include an alpha channel. The default RGB format + // causes Cocoa to spend an unreasonable amount of time converting it to RGBA internally. + if (format == QSurfaceFormat()) + format.setAlphaBufferSize(8); + return format; } void QCocoaWindow::setGeometry(const QRect &rectIn) @@ -688,8 +696,10 @@ void QCocoaWindow::setVisible(bool visible) && [m_nsWindow isKindOfClass:[NSPanel class]]) { [(NSPanel *)m_nsWindow setWorksWhenModal:YES]; if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) { - monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDown handler:^(NSEvent *) { - QWindowSystemInterface::handleMouseEvent(window(), QPointF(-1, -1), QPointF(window()->framePosition() - QPointF(1, 1)), Qt::LeftButton); + monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) { + QPointF localPoint = qt_mac_flipPoint([NSEvent mouseLocation]); + QWindowSystemInterface::handleMouseEvent(window(), window()->mapFromGlobal(localPoint.toPoint()), localPoint, + cocoaButton2QtButton([e buttonNumber])); }]; } } @@ -789,9 +799,22 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) if (flags & Qt::FramelessWindowHint) return styleMask; if ((type & Qt::Popup) == Qt::Popup) { - if (!windowIsPopupType(type)) - styleMask = (NSUtilityWindowMask | NSResizableWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSTitledWindowMask); + if (!windowIsPopupType(type)) { + styleMask = NSUtilityWindowMask; + if (!(flags & Qt::CustomizeWindowHint)) { + styleMask |= NSResizableWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | NSTitledWindowMask; + } else { + if (flags & Qt::WindowMaximizeButtonHint) + styleMask |= NSResizableWindowMask; + if (flags & Qt::WindowTitleHint) + styleMask |= NSTitledWindowMask; + if (flags & Qt::WindowCloseButtonHint) + styleMask |= NSClosableWindowMask; + if (flags & Qt::WindowMinimizeButtonHint) + styleMask |= NSMiniaturizableWindowMask; + } + } } else { if (type == Qt::Window && !(flags & Qt::CustomizeWindowHint)) { styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask); @@ -1235,7 +1258,9 @@ QCocoaGLContext *QCocoaWindow::currentContext() const void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) { bool wasNSWindowChild = m_isNSWindowChild; - m_isNSWindowChild = parentWindow && (window()->property("_q_platform_MacUseNSWindow").toBool()); + BOOL requestNSWindowChild = qt_mac_resolveOption(NO, window(), "_q_platform_MacUseNSWindow", + "QT_MAC_USE_NSWINDOW"); + m_isNSWindowChild = parentWindow && requestNSWindowChild; bool needsNSWindow = m_isNSWindowChild || !parentWindow; QCocoaWindow *oldParentCocoaWindow = m_parentCocoaWindow; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index df4ebec88b..c71c9f0680 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1849,41 +1849,9 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin return NO; } -- (NSDragOperation)draggingEntered:(id )sender +- (void)updateCursorFromDragResponse:(QPlatformDragQtResponse)response drag:(QCocoaDrag *)drag { - return [self handleDrag : sender]; -} - -- (NSDragOperation)draggingUpdated:(id )sender -{ - return [self handleDrag : sender]; -} - -// Sends drag update to Qt, return the action -- (NSDragOperation)handleDrag:(id )sender -{ - NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; - QPoint qt_windowPoint(windowPoint.x, windowPoint.y); - Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); - - QWindow *target = findEventTargetWindow(m_window); - if (!target) - return NSDragOperationNone; - - // update these so selecting move/copy/link works - QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]]; - - QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect()); - if ([sender draggingSource] != nil) { - QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); - response = QWindowSystemInterface::handleDrag(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); - } else { - QCocoaDropData mimeData([sender draggingPasteboard]); - response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); - } - - QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); - const QPixmap pixmapCursor = nativeDrag->currentDrag()->dragCursor(response.acceptedAction()); + const QPixmap pixmapCursor = drag->currentDrag()->dragCursor(response.acceptedAction()); NSCursor *nativeCursor = nil; if (pixmapCursor.isNull()) { @@ -1923,6 +1891,41 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin )); CGEventPost(kCGHIDEventTap, moveEvent); CFRelease(moveEvent); +} + +- (NSDragOperation)draggingEntered:(id )sender +{ + return [self handleDrag : sender]; +} + +- (NSDragOperation)draggingUpdated:(id )sender +{ + return [self handleDrag : sender]; +} + +// Sends drag update to Qt, return the action +- (NSDragOperation)handleDrag:(id )sender +{ + NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil]; + QPoint qt_windowPoint(windowPoint.x, windowPoint.y); + Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]); + + QWindow *target = findEventTargetWindow(m_window); + if (!target) + return NSDragOperationNone; + + // update these so selecting move/copy/link works + QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]]; + + QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect()); + if ([sender draggingSource] != nil) { + QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); + response = QWindowSystemInterface::handleDrag(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); + [self updateCursorFromDragResponse:response drag:nativeDrag]; + } else { + QCocoaDropData mimeData([sender draggingPasteboard]); + response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed); + } return qt_mac_mapDropAction(response.acceptedAction()); } diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm index a2285d8a4f..cb3e6e2cc5 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm @@ -49,7 +49,7 @@ QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode) : QPaintEngine(*(ne { Q_D(QMacPrintEngine); d->mode = mode; - d->m_printDevice = new QCocoaPrintDevice(QCocoaPrinterSupport().defaultPrintDeviceId()); + d->m_printDevice.reset(new QCocoaPrintDevice(QCocoaPrinterSupport().defaultPrintDeviceId())); d->m_pageLayout.setPageSize(d->m_printDevice->defaultPageSize()); d->initialize(); } @@ -557,7 +557,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va id = QCocoaPrinterSupport().defaultPrintDeviceId(); else if (!QCocoaPrinterSupport().availablePrintDeviceIds().contains(id)) break; - d->m_printDevice = new QCocoaPrintDevice(id); + d->m_printDevice.reset(new QCocoaPrintDevice(id)); PMPrinter printer = d->m_printDevice->macPrinter(); PMRetain(printer); PMSessionSetCurrentPMPrinter(d->session(), printer); diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h index 6a795a55d8..494fb5b9d1 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h +++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h @@ -116,7 +116,7 @@ class QMacPrintEnginePrivate : public QPaintEnginePrivate public: QPrinter::PrinterMode mode; QPrinter::PrinterState state; - QSharedDataPointer m_printDevice; + QSharedPointer m_printDevice; QPageLayout m_pageLayout; NSPrintInfo *printInfo; PMResolution resolution; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index d439196dc1..16c05329de 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -358,10 +358,10 @@ public: } 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 + FLOAT(points[0]), // left + FLOAT(points[1]), // top + FLOAT(points[2]), // right, + FLOAT(points[5]) // bottom }; dc()->PushAxisAlignedClip(rect, antialiasMode()); @@ -918,13 +918,13 @@ public: DWRITE_GLYPH_RUN glyphRun = { fontFace, // IDWriteFontFace *fontFace; - fontDef.pixelSize, // FLOAT fontEmSize; - numGlyphs, // UINT32 glyphCount; + FLOAT(fontDef.pixelSize), // FLOAT fontEmSize; + UINT32(numGlyphs), // UINT32 glyphCount; glyphIndices, // const UINT16 *glyphIndices; glyphAdvances, // const FLOAT *glyphAdvances; glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets; FALSE, // BOOL isSideways; - rtl ? 1 : 0 // UINT32 bidiLevel; + rtl ? 1u : 0u // UINT32 bidiLevel; }; const bool antiAlias = bool((q->state()->renderHints & QPainter::TextAntialiasing) @@ -1393,8 +1393,8 @@ void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &r) D2D1_ELLIPSE ellipse = { to_d2d_point_2f(p), - r.width() / 2.0, - r.height() / 2.0 + FLOAT(r.width() / 2.0), + FLOAT(r.height() / 2.0) }; if (d->brush.brush) @@ -1421,8 +1421,8 @@ void QWindowsDirect2DPaintEngine::drawEllipse(const QRect &r) D2D1_ELLIPSE ellipse = { to_d2d_point_2f(p), - r.width() / 2.0, - r.height() / 2.0 + FLOAT(r.width() / 2.0), + FLOAT(r.height() / 2.0) }; if (d->brush.brush) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp index ab4be67bbe..e4cc163b9e 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp @@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE class QWindowsDirect2DIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "direct2d.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "direct2d.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index e762eab711..ba23526447 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -163,7 +163,7 @@ void QWindowsDirect2DWindow::present(const QRegion ®ion) const SIZE size = { bounds.width(), bounds.height() }; const POINT ptDst = { bounds.x(), bounds.y() }; const POINT ptSrc = { 0, 0 }; - const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255.0 * opacity(), AC_SRC_ALPHA }; + const BLENDFUNCTION blend = { AC_SRC_OVER, 0, BYTE(255.0 * opacity()), AC_SRC_ALPHA }; const QRect r = region.boundingRect(); const RECT dirty = { r.left(), r.top(), r.left() + r.width(), r.top() + r.height() }; UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), NULL, diff --git a/src/plugins/platforms/directfb/main.cpp b/src/plugins/platforms/directfb/main.cpp index 3faa7c9a8b..4308a164ae 100644 --- a/src/plugins/platforms/directfb/main.cpp +++ b/src/plugins/platforms/directfb/main.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE class QDirectFbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "directfb.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "directfb.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmscursor.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmscursor.cpp index cd92c49ff1..fe47c947b4 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmscursor.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmscursor.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2015 Pier Luigi Fiorini ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -87,8 +88,11 @@ QEglFSKmsCursor::QEglFSKmsCursor(QEglFSKmsScreen *screen) QEglFSKmsCursor::~QEglFSKmsCursor() { - drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0, 0); - drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0); + Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) { + QEglFSKmsScreen *kmsScreen = static_cast(screen); + drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0, 0); + drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0); + } gbm_bo_destroy(m_bo); m_bo = Q_NULLPTR; @@ -143,10 +147,15 @@ void QEglFSKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window) gbm_bo_write(m_bo, cursorImage.constBits(), cursorImage.byteCount()); uint32_t handle = gbm_bo_get_handle(m_bo).u32; - int status = drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, handle, - m_cursorSize.width(), m_cursorSize.height()); - if (status != 0) - qWarning("Could not set cursor: %d", status); + + Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) { + QEglFSKmsScreen *kmsScreen = static_cast(screen); + + int status = drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, handle, + m_cursorSize.width(), m_cursorSize.height()); + if (status != 0) + qWarning("Could not set cursor on screen %s: %d", kmsScreen->name().toLatin1().constData(), status); + } } #endif // QT_NO_CURSOR @@ -157,12 +166,17 @@ QPoint QEglFSKmsCursor::pos() const void QEglFSKmsCursor::setPos(const QPoint &pos) { - QPoint adjustedPos = pos - m_cursorImage.hotspot(); - int ret = drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, adjustedPos.x(), adjustedPos.y()); - if (ret == 0) { - m_pos = pos; - } else { - qWarning("Failed to move cursor: %d", ret); + Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) { + QEglFSKmsScreen *kmsScreen = static_cast(screen); + QPoint origin = kmsScreen->geometry().topLeft(); + QPoint localPos = pos - origin; + QPoint adjustedPos = localPos - m_cursorImage.hotspot(); + + int ret = drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, adjustedPos.x(), adjustedPos.y()); + if (ret == 0) + m_pos = pos; + else + qWarning("Failed to move cursor on screen %s: %d", kmsScreen->name().toLatin1().constData(), ret); } } @@ -176,8 +190,11 @@ void QEglFSKmsCursor::initCursorAtlas() QFile file(QString::fromUtf8(json)); if (!file.open(QFile::ReadOnly)) { - drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0, 0); - drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0); + Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) { + QEglFSKmsScreen *kmsScreen = static_cast(screen); + drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0, 0); + drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0); + } m_visible = false; return; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp index bafe1e3324..18a66e34f5 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2015 Pier Luigi Fiorini ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -308,6 +309,7 @@ QEglFSKmsDevice::QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QStrin , m_gbm_device(Q_NULLPTR) , m_crtc_allocator(0) , m_connector_allocator(0) + , m_globalCursor(Q_NULLPTR) { } @@ -347,6 +349,10 @@ void QEglFSKmsDevice::close() qt_safe_close(m_dri_fd); m_dri_fd = -1; } + + if (m_globalCursor) + m_globalCursor->deleteLater(); + m_globalCursor = Q_NULLPTR; } void QEglFSKmsDevice::createScreens() @@ -357,6 +363,8 @@ void QEglFSKmsDevice::createScreens() return; } + QEglFSKmsScreen *primaryScreen = Q_NULLPTR; + QList siblings; QPoint pos(0, 0); QEglFSIntegration *integration = static_cast(QGuiApplicationPrivate::platformIntegration()); @@ -369,12 +377,24 @@ void QEglFSKmsDevice::createScreens() if (screen) { integration->addScreen(screen); pos.rx() += screen->geometry().width(); + siblings << screen; + + if (!primaryScreen) + primaryScreen = screen; } drmModeFreeConnector(connector); } drmModeFreeResources(resources); + + if (!m_integration->separateScreens()) { + Q_FOREACH (QPlatformScreen *screen, siblings) + static_cast(screen)->setVirtualSiblings(siblings); + + if (primaryScreen) + m_globalCursor = new QEglFSKmsCursor(primaryScreen); + } } gbm_device *QEglFSKmsDevice::device() const @@ -387,6 +407,11 @@ int QEglFSKmsDevice::fd() const return m_dri_fd; } +QPlatformCursor *QEglFSKmsDevice::globalCursor() const +{ + return m_globalCursor; +} + void QEglFSKmsDevice::handleDrmEvent() { drmEventContext drmEvent = { diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.h index 29a1332c9a..23fca934e5 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2015 Pier Luigi Fiorini ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -34,6 +35,7 @@ #ifndef QEGLFSKMSDEVICE_H #define QEGLFSKMSDEVICE_H +#include "qeglfskmscursor.h" #include "qeglfskmsintegration.h" #include @@ -57,6 +59,8 @@ public: gbm_device *device() const; int fd() const; + QPlatformCursor *globalCursor() const; + void handleDrmEvent(); private: @@ -70,6 +74,8 @@ private: quint32 m_crtc_allocator; quint32 m_connector_allocator; + QEglFSKmsCursor *m_globalCursor; + int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector); QEglFSKmsScreen *screenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, QPoint pos); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.cpp index 7bb932cf00..45224ccb87 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2015 Pier Luigi Fiorini ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -60,6 +61,7 @@ QEglFSKmsIntegration::QEglFSKmsIntegration() : m_device(Q_NULLPTR) , m_hwCursor(true) , m_pbuffers(false) + , m_separateScreens(false) {} void QEglFSKmsIntegration::platformInit() @@ -203,6 +205,11 @@ bool QEglFSKmsIntegration::hwCursor() const return m_hwCursor; } +bool QEglFSKmsIntegration::separateScreens() const +{ + return m_separateScreens; +} + QMap QEglFSKmsIntegration::outputSettings() const { return m_outputSettings; @@ -235,6 +242,7 @@ void QEglFSKmsIntegration::loadConfig() m_hwCursor = object.value(QStringLiteral("hwcursor")).toBool(m_hwCursor); m_pbuffers = object.value(QStringLiteral("pbuffers")).toBool(m_pbuffers); m_devicePath = object.value(QStringLiteral("device")).toString(); + m_separateScreens = object.value(QStringLiteral("separateScreens")).toBool(m_separateScreens); const QJsonArray outputs = object.value(QStringLiteral("outputs")).toArray(); for (int i = 0; i < outputs.size(); i++) { @@ -254,6 +262,7 @@ void QEglFSKmsIntegration::loadConfig() qCDebug(qLcEglfsKmsDebug) << "Configuration:\n" << "\thwcursor:" << m_hwCursor << "\n" << "\tpbuffers:" << m_pbuffers << "\n" + << "\tseparateScreens:" << m_separateScreens << "\n" << "\toutputs:" << m_outputSettings; } diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.h index 9a160d2570..edb6906a4b 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2015 Pier Luigi Fiorini ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -65,6 +66,7 @@ public: bool supportsPBuffers() const Q_DECL_OVERRIDE; bool hwCursor() const; + bool separateScreens() const; QMap outputSettings() const; private: @@ -73,6 +75,7 @@ private: QEglFSKmsDevice *m_device; bool m_hwCursor; bool m_pbuffers; + bool m_separateScreens; QString m_devicePath; QMap m_outputSettings; }; diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp index a27819d1dd..5e49c224a0 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2015 Pier Luigi Fiorini ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -120,6 +121,7 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration, , m_cursor(Q_NULLPTR) , m_interruptHandler(new QEglFSKmsInterruptHandler(this)) { + m_siblings << this; } QEglFSKmsScreen::~QEglFSKmsScreen() @@ -185,6 +187,9 @@ QString QEglFSKmsScreen::name() const QPlatformCursor *QEglFSKmsScreen::cursor() const { if (m_integration->hwCursor()) { + if (!m_integration->separateScreens()) + return m_device->globalCursor(); + if (m_cursor.isNull()) { QEglFSKmsScreen *that = const_cast(this); that->m_cursor.reset(new QEglFSKmsCursor(that)); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h index 16521c7fe0..4c1b0d02ad 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2015 Pier Luigi Fiorini ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** @@ -85,6 +86,10 @@ public: qreal refreshRate() const Q_DECL_OVERRIDE; + QList virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; } + void setVirtualSiblings(QList sl) { m_siblings = sl; } + + QEglFSKmsIntegration *integration() const { return m_integration; } QEglFSKmsDevice *device() const { return m_device; } gbm_surface *surface() const { return m_gbm_surface; } @@ -110,6 +115,8 @@ private: QPoint m_pos; QScopedPointer m_cursor; + QList m_siblings; + struct FrameBuffer { FrameBuffer() : fb(0) {} uint32_t fb; diff --git a/src/plugins/platforms/eglfs/qeglfsmain.cpp b/src/plugins/platforms/eglfs/qeglfsmain.cpp index 4aae7118ac..89b2f20569 100644 --- a/src/plugins/platforms/eglfs/qeglfsmain.cpp +++ b/src/plugins/platforms/eglfs/qeglfsmain.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QEglFSIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "eglfs.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "eglfs.json") public: QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index 30fdce9fd3..c0d51c94a5 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +107,7 @@ void QEglFSWindow::create() if (isRaster()) { QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance()); + context->setShareContext(qt_gl_global_share_context()); context->setFormat(m_format); context->setScreen(window()->screen()); if (!context->create()) diff --git a/src/plugins/platforms/haiku/main.h b/src/plugins/platforms/haiku/main.h index fbf0bee527..9889109c7e 100644 --- a/src/plugins/platforms/haiku/main.h +++ b/src/plugins/platforms/haiku/main.h @@ -38,7 +38,7 @@ QT_BEGIN_NAMESPACE class QHaikuIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "haiku.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "haiku.json") public: QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm index 41fe712f60..e68e1dfd6f 100644 --- a/src/plugins/platforms/ios/plugin.mm +++ b/src/plugins/platforms/ios/plugin.mm @@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "ios.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "ios.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/ios/qiosbackingstore.h b/src/plugins/platforms/ios/qiosbackingstore.h index 68c77d9900..5d2ae429f1 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.h +++ b/src/plugins/platforms/ios/qiosbackingstore.h @@ -39,6 +39,8 @@ QT_BEGIN_NAMESPACE class QOpenGLPaintDevice; +class QOpenGLFramebufferObject; +class QOffscreenSurface; class QIOSBackingStore : public QPlatformBackingStore { @@ -49,13 +51,19 @@ public: QPaintDevice *paintDevice(); void beginPaint(const QRegion &); + void endPaint(); void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); void resize(const QSize &size, const QRegion &staticContents); + GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const; + + void makeCurrent(); private: QOpenGLContext *m_context; QOpenGLPaintDevice *m_device; + QOpenGLFramebufferObject *m_fbo; + QOffscreenSurface *m_surface; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm index acec95b0d3..875d06dc80 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.mm +++ b/src/plugins/platforms/ios/qiosbackingstore.mm @@ -36,41 +36,117 @@ #include #include +#include +#include +#include #include +class QIOSPaintDevice : public QOpenGLPaintDevice +{ +public: + QIOSPaintDevice(QIOSBackingStore *backingStore) : m_backingStore(backingStore) { } + void ensureActiveTarget() Q_DECL_OVERRIDE; + +private: + QIOSBackingStore *m_backingStore; +}; + +void QIOSPaintDevice::ensureActiveTarget() +{ + m_backingStore->makeCurrent(); +} + QIOSBackingStore::QIOSBackingStore(QWindow *window) : QPlatformBackingStore(window) , m_context(new QOpenGLContext) , m_device(0) + , m_fbo(0) + , m_surface(0) { QSurfaceFormat fmt = window->requestedFormat(); - fmt.setDepthBufferSize(16); - fmt.setStencilBufferSize(8); + // Due to sharing QIOSContext redirects our makeCurrent on window() attempts to + // the global share context. Hence it is essential to have a compatible format. + fmt.setDepthBufferSize(QSurfaceFormat::defaultFormat().depthBufferSize()); + fmt.setStencilBufferSize(QSurfaceFormat::defaultFormat().stencilBufferSize()); - // Needed to prevent QOpenGLContext::makeCurrent() from failing - window->setSurfaceType(QSurface::OpenGLSurface); + if (fmt.depthBufferSize() == 0) + qWarning("No depth in default format, expect rendering errors"); + + if (window->surfaceType() == QSurface::RasterSurface) + window->setSurfaceType(QSurface::OpenGLSurface); m_context->setFormat(fmt); m_context->setScreen(window->screen()); + Q_ASSERT(QOpenGLContext::globalShareContext()); + m_context->setShareContext(QOpenGLContext::globalShareContext()); m_context->create(); } QIOSBackingStore::~QIOSBackingStore() { + delete m_fbo; + delete m_surface; delete m_context; delete m_device; } +void QIOSBackingStore::makeCurrent() +{ + QSurface *surface = m_surface ? m_surface : static_cast(window()); + if (!m_context->makeCurrent(surface)) + qWarning("QIOSBackingStore: makeCurrent() failed"); + if (m_fbo) + m_fbo->bind(); +} + void QIOSBackingStore::beginPaint(const QRegion &) { - m_context->makeCurrent(window()); + if (qt_window_private(window())->compositing) { + if (!m_fbo) { + delete m_device; + m_device = 0; + } + if (!m_surface) { + m_surface = new QOffscreenSurface; + m_surface->setFormat(m_context->format()); + m_surface->create(); + } + if (!m_context->makeCurrent(m_surface)) + qWarning("QIOSBackingStore: Failed to make offscreen surface current"); + const QSize size = window()->size() * window()->devicePixelRatio(); + if (m_fbo && m_fbo->size() != size) { + delete m_fbo; + m_fbo = 0; + } + if (!m_fbo) + m_fbo = new QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::CombinedDepthStencil); + } else if (m_fbo) { + delete m_fbo; + m_fbo = 0; + delete m_surface; + m_surface = 0; + delete m_device; + m_device = 0; + } + + makeCurrent(); + + if (!m_device) + m_device = new QIOSPaintDevice(this); +} + +void QIOSBackingStore::endPaint() +{ + if (m_fbo) { + m_fbo->release(); + glFlush(); + } } QPaintDevice *QIOSBackingStore::paintDevice() { - if (!m_device) - m_device = new QOpenGLPaintDevice; + Q_ASSERT(m_device); // Keep paint device size and device pixel ratio in sync with window qreal devicePixelRatio = window()->devicePixelRatio(); @@ -82,6 +158,8 @@ QPaintDevice *QIOSBackingStore::paintDevice() void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { + Q_ASSERT(!qt_window_private(window)->compositing); + Q_UNUSED(region); Q_UNUSED(offset); @@ -111,4 +189,21 @@ void QIOSBackingStore::resize(const QSize &size, const QRegion &staticContents) qWarning() << "QIOSBackingStore needs to have the same size as its window"; } +GLuint QIOSBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const +{ + Q_ASSERT(qt_window_private(window())->compositing); + Q_UNUSED(dirtyRegion); + + if (flags) + *flags = TextureFlip; + + if (!m_fbo) + return 0; + + if (textureSize) + *textureSize = m_fbo->size(); + + return m_fbo->texture(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index c7541fc51b..fe0ca33c13 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -116,7 +116,8 @@ static QString fboStatusString(GLenum status) bool QIOSContext::makeCurrent(QPlatformSurface *surface) { - Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface); + Q_ASSERT(surface && (surface->surface()->surfaceType() == QSurface::OpenGLSurface + || surface->surface()->surfaceType() == QSurface::RasterGLSurface)); [EAGLContext setCurrentContext:m_eaglContext]; @@ -141,7 +142,8 @@ void QIOSContext::doneCurrent() void QIOSContext::swapBuffers(QPlatformSurface *surface) { - Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface); + Q_ASSERT(surface && (surface->surface()->surfaceType() == QSurface::OpenGLSurface + || surface->surface()->surfaceType() == QSurface::RasterGLSurface)); if (surface->surface()->surfaceClass() == QSurface::Offscreen) return; // Nothing to do diff --git a/src/plugins/platforms/ios/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/qiosfileengineassetslibrary.h index 043e101a21..37bbc7bf23 100644 --- a/src/plugins/platforms/ios/qiosfileengineassetslibrary.h +++ b/src/plugins/platforms/ios/qiosfileengineassetslibrary.h @@ -55,10 +55,17 @@ public: QString fileName(FileName file) const Q_DECL_OVERRIDE; void setFileName(const QString &file) Q_DECL_OVERRIDE; QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const Q_DECL_OVERRIDE; + +#ifndef QT_NO_FILESYSTEMITERATOR + Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE; + Iterator *endEntryList() Q_DECL_OVERRIDE; +#endif + void setError(QFile::FileError error, const QString &str) { QAbstractFileEngine::setError(error, str); } private: QString m_fileName; + QString m_assetUrl; qint64 m_offset; mutable QIOSAssetData *m_data; diff --git a/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm index 73bfc2a87f..44a7901160 100644 --- a/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm +++ b/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm @@ -38,6 +38,145 @@ #include #include +#include +#include +#include + +static QThreadStorage g_iteratorCurrentUrl; +static QThreadStorage > g_assetDataCache; + +static const int kBufferSize = 10; +static ALAsset *kNoAsset = 0; + +static void ensureAuthorizationDialogNotBlocked() +{ + if ([ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusNotDetermined) + return; + if (static_cast(QObjectPrivate::get(qApp))->in_exec) + return; + + // Since authorization status has not been determined, the user will be asked + // to authorize the app. But since main has not finished, the dialog will be held + // back until the launch completes. To avoid a dead-lock below, we start an event + // loop to complete the launch. + QEventLoop loop; + QTimer::singleShot(1, &loop, &QEventLoop::quit); + loop.exec(); +} + +// ------------------------------------------------------------------------- + +class QIOSAssetEnumerator +{ +public: + QIOSAssetEnumerator(ALAssetsLibrary *assetsLibrary, ALAssetsGroupType type) + : m_semWriteAsset(dispatch_semaphore_create(kBufferSize)) + , m_semReadAsset(dispatch_semaphore_create(0)) + , m_stop(false) + , m_assetsLibrary([assetsLibrary retain]) + , m_type(type) + , m_buffer(QVector(kBufferSize)) + , m_readIndex(0) + , m_writeIndex(0) + , m_nextAssetReady(false) + { + ensureAuthorizationDialogNotBlocked(); + startEnumerate(); + } + + ~QIOSAssetEnumerator() + { + m_stop = true; + + // Flush and autorelease remaining assets in the buffer + while (hasNext()) + next(); + + // Documentation states that we need to balance out calls to 'wait' + // and 'signal'. Since the enumeration function always will be one 'wait' + // ahead, we need to signal m_semProceedToNextAsset one last time. + dispatch_semaphore_signal(m_semWriteAsset); + dispatch_release(m_semReadAsset); + dispatch_release(m_semWriteAsset); + + [m_assetsLibrary autorelease]; + } + + bool hasNext() + { + if (!m_nextAssetReady) { + dispatch_semaphore_wait(m_semReadAsset, DISPATCH_TIME_FOREVER); + m_nextAssetReady = true; + } + return m_buffer[m_readIndex] != kNoAsset; + } + + ALAsset *next() + { + Q_ASSERT(m_nextAssetReady); + Q_ASSERT(m_buffer[m_readIndex]); + + ALAsset *asset = [m_buffer[m_readIndex] autorelease]; + dispatch_semaphore_signal(m_semWriteAsset); + + m_readIndex = (m_readIndex + 1) % kBufferSize; + m_nextAssetReady = false; + return asset; + } + +private: + dispatch_semaphore_t m_semWriteAsset; + dispatch_semaphore_t m_semReadAsset; + std::atomic_bool m_stop; + + ALAssetsLibrary *m_assetsLibrary; + ALAssetsGroupType m_type; + QVector m_buffer; + int m_readIndex; + int m_writeIndex; + bool m_nextAssetReady; + + void writeAsset(ALAsset *asset) + { + dispatch_semaphore_wait(m_semWriteAsset, DISPATCH_TIME_FOREVER); + m_buffer[m_writeIndex] = [asset retain]; + dispatch_semaphore_signal(m_semReadAsset); + m_writeIndex = (m_writeIndex + 1) % kBufferSize; + } + + void startEnumerate() + { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [m_assetsLibrary enumerateGroupsWithTypes:m_type usingBlock:^(ALAssetsGroup *group, BOOL *stopEnumerate) { + + if (!group) { + writeAsset(kNoAsset); + return; + } + + if (m_stop) { + *stopEnumerate = true; + return; + } + + [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stopEnumerate) { + Q_UNUSED(index); + if (!asset || ![[asset valueForProperty:ALAssetPropertyType] isEqual:ALAssetTypePhoto]) + return; + + writeAsset(asset); + *stopEnumerate = m_stop; + }]; + } failureBlock:^(NSError *error) { + NSLog(@"QIOSFileEngine: %@", error); + writeAsset(kNoAsset); + }]; + }); + } + +}; + +// ------------------------------------------------------------------------- class QIOSAssetData : public QObject { @@ -47,35 +186,17 @@ public: , m_assetUrl(assetUrl) , m_assetLibrary(0) { - switch ([ALAssetsLibrary authorizationStatus]) { - case ALAuthorizationStatusRestricted: - case ALAuthorizationStatusDenied: - engine->setError(QFile::PermissionsError, QLatin1String("Unauthorized access")); - return; - case ALAuthorizationStatusNotDetermined: - if (!static_cast(QObjectPrivate::get(qApp))->in_exec) { - // Since authorization status has not been determined, the user will be asked - // to authorize the app. But since main has not finished, the dialog will be held - // back until the launch completes. To avoid a dead-lock below, we start an event - // loop to complete the launch. - QEventLoop loop; - QTimer::singleShot(1, &loop, &QEventLoop::quit); - loop.exec(); - } - break; - default: - if (g_currentAssetData) { - // It's a common pattern that QFiles pointing to the same path are created and destroyed - // several times during a single event loop cycle. To avoid loading the same asset - // over and over, we check if the last loaded asset has not been destroyed yet, and try to - // reuse its data. Since QFile is (mostly) reentrant, we need to protect m_currentAssetData - // from being modified by several threads at the same time. - QMutexLocker lock(&g_mutex); - if (g_currentAssetData && g_currentAssetData->m_assetUrl == assetUrl) { - m_assetLibrary = [g_currentAssetData->m_assetLibrary retain]; - m_asset = [g_currentAssetData->m_asset retain]; - return; - } + ensureAuthorizationDialogNotBlocked(); + + if (QIOSAssetData *assetData = g_assetDataCache.localData()) { + // It's a common pattern that QFiles pointing to the same path are created and destroyed + // several times during a single event loop cycle. To avoid loading the same asset + // over and over, we check if the last loaded asset has not been destroyed yet, and try to + // reuse its data. + if (assetData->m_assetUrl == assetUrl) { + m_assetLibrary = [assetData->m_assetLibrary retain]; + m_asset = [assetData->m_asset retain]; + return; } } @@ -90,6 +211,26 @@ public: NSURL *url = [NSURL URLWithString:assetUrl.toNSString()]; m_assetLibrary = [[ALAssetsLibrary alloc] init]; [m_assetLibrary assetForURL:url resultBlock:^(ALAsset *asset) { + + if (!asset) { + // When an asset couldn't be loaded, chances are that it belongs to ALAssetsGroupPhotoStream. + // Such assets can be stored in the cloud and might need to be downloaded first. Unfortunately, + // forcing that to happen is hidden behind private APIs ([ALAsset requestDefaultRepresentation]). + // As a work-around, we search for it instead, since that will give us a pointer to the asset. + QIOSAssetEnumerator e(m_assetLibrary, ALAssetsGroupPhotoStream); + while (e.hasNext()) { + ALAsset *a = e.next(); + QString url = QUrl::fromNSURL([a valueForProperty:ALAssetPropertyAssetURL]).toString(); + if (url == assetUrl) { + asset = a; + break; + } + } + } + + if (!asset) + engine->setError(QFile::OpenError, QLatin1String("could not open image")); + m_asset = [asset retain]; dispatch_semaphore_signal(semaphore); } failureBlock:^(NSError *error) { @@ -101,17 +242,15 @@ public: dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_release(semaphore); - QMutexLocker lock(&g_mutex); - g_currentAssetData = this; + g_assetDataCache.setLocalData(this); } ~QIOSAssetData() { - QMutexLocker lock(&g_mutex); [m_assetLibrary release]; [m_asset release]; - if (this == g_currentAssetData) - g_currentAssetData = 0; + if (g_assetDataCache.localData() == this) + g_assetDataCache.setLocalData(0); } ALAsset *m_asset; @@ -119,21 +258,67 @@ public: private: QString m_assetUrl; ALAssetsLibrary *m_assetLibrary; - - static QBasicMutex g_mutex; - static QPointer g_currentAssetData; }; -QBasicMutex QIOSAssetData::g_mutex; -QPointer QIOSAssetData::g_currentAssetData = 0; +// ------------------------------------------------------------------------- + +#ifndef QT_NO_FILESYSTEMITERATOR + +class QIOSFileEngineIteratorAssetsLibrary : public QAbstractFileEngineIterator +{ +public: + QIOSAssetEnumerator *m_enumerator; + + QIOSFileEngineIteratorAssetsLibrary( + QDir::Filters filters, const QStringList &nameFilters) + : QAbstractFileEngineIterator(filters, nameFilters) + , m_enumerator(new QIOSAssetEnumerator([[[ALAssetsLibrary alloc] init] autorelease], ALAssetsGroupAll)) + { + } + + ~QIOSFileEngineIteratorAssetsLibrary() + { + delete m_enumerator; + g_iteratorCurrentUrl.setLocalData(QString()); + } + + QString next() Q_DECL_OVERRIDE + { + // Cache the URL that we are about to return, since QDir will immediately create a + // new file engine on the file and ask if it exists. Unless we do this, we end up + // creating a new ALAsset just to verify its existence, which will be especially + // costly for assets belonging to ALAssetsGroupPhotoStream. + ALAsset *asset = m_enumerator->next(); + QString url = QUrl::fromNSURL([asset valueForProperty:ALAssetPropertyAssetURL]).toString(); + g_iteratorCurrentUrl.setLocalData(url); + return url; + } + + bool hasNext() const Q_DECL_OVERRIDE + { + return m_enumerator->hasNext(); + } + + QString currentFileName() const Q_DECL_OVERRIDE + { + return g_iteratorCurrentUrl.localData(); + } + + QFileInfo currentFileInfo() const + { + return QFileInfo(currentFileName()); + } +}; + +#endif // ------------------------------------------------------------------------- QIOSFileEngineAssetsLibrary::QIOSFileEngineAssetsLibrary(const QString &fileName) - : m_fileName(fileName) - , m_offset(0) + : m_offset(0) , m_data(0) { + setFileName(fileName); } QIOSFileEngineAssetsLibrary::~QIOSFileEngineAssetsLibrary() @@ -143,18 +328,8 @@ QIOSFileEngineAssetsLibrary::~QIOSFileEngineAssetsLibrary() ALAsset *QIOSFileEngineAssetsLibrary::loadAsset() const { - if (!m_data) { - // QUrl::fromLocalFile() will remove double slashes. Since the asset url is passed around as a file - // name in the app (and converted to/from a file url, e.g in QFileDialog), we need to check if we still - // have two leading slashes after the scheme, and restore the second slash if not. - QString assetUrl = m_fileName; - const int index = 16; // "assets-library://" - if (assetUrl[index] != QLatin1Char('/')) - assetUrl.insert(index, '/'); - - m_data = new QIOSAssetData(assetUrl, const_cast(this)); - } - + if (!m_data) + m_data = new QIOSAssetData(m_assetUrl, const_cast(this)); return m_data->m_asset; } @@ -179,15 +354,21 @@ bool QIOSFileEngineAssetsLibrary::close() QAbstractFileEngine::FileFlags QIOSFileEngineAssetsLibrary::fileFlags(QAbstractFileEngine::FileFlags type) const { QAbstractFileEngine::FileFlags flags = 0; - if (!loadAsset()) + const bool isDir = (m_assetUrl == QLatin1String("assets-library://")); + const bool exists = isDir || m_assetUrl == g_iteratorCurrentUrl.localData() || loadAsset(); + + if (!exists) return flags; if (type & FlagsMask) flags |= ExistsFlag; - if (type & PermsMask) - flags |= ReadOwnerPerm | ReadUserPerm | ReadGroupPerm | ReadOtherPerm; + if (type & PermsMask) { + ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus]; + if (status != ALAuthorizationStatusRestricted && status != ALAuthorizationStatusDenied) + flags |= ReadOwnerPerm | ReadUserPerm | ReadGroupPerm | ReadOtherPerm; + } if (type & TypesMask) - flags |= FileType; + flags |= isDir ? DirectoryType : FileType; return flags; } @@ -245,11 +426,32 @@ void QIOSFileEngineAssetsLibrary::setFileName(const QString &file) if (m_data) close(); m_fileName = file; + // QUrl::fromLocalFile() will remove double slashes. Since the asset url is + // passed around as a file name in the app (and converted to/from a file url, e.g + // in QFileDialog), we need to ensure that m_assetUrl ends up being valid. + int index = file.indexOf(QLatin1String("asset.JPG?")); + if (index == -1) + m_assetUrl = QLatin1String("assets-library://"); + else + m_assetUrl = QLatin1String("assets-library://asset/") + file.mid(index); } QStringList QIOSFileEngineAssetsLibrary::entryList(QDir::Filters filters, const QStringList &filterNames) const { - Q_UNUSED(filters); - Q_UNUSED(filterNames); - return QStringList(); + return QAbstractFileEngine::entryList(filters, filterNames); } + +#ifndef QT_NO_FILESYSTEMITERATOR + +QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::beginEntryList( + QDir::Filters filters, const QStringList &filterNames) +{ + return new QIOSFileEngineIteratorAssetsLibrary(filters, filterNames); +} + +QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::endEntryList() +{ + return 0; +} + +#endif diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 986fef7725..b4050b8f62 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -77,6 +77,15 @@ QIOSIntegration::QIOSIntegration() "'applicationDidFinishLaunching' inside your UIApplication delegate.\n"); } + // The backingstore needs a global share context in order to support composition in + // QPlatformBackingStore. + qApp->setAttribute(Qt::AA_ShareOpenGLContexts, true); + // And that context must match the format used for the backingstore's context. + QSurfaceFormat fmt; + fmt.setDepthBufferSize(16); + fmt.setStencilBufferSize(8); + QSurfaceFormat::setDefaultFormat(fmt); + // Set current directory to app bundle folder QDir::setCurrent(QString::fromUtf8([[[NSBundle mainBundle] bundlePath] UTF8String])); @@ -137,6 +146,8 @@ bool QIOSIntegration::hasCapability(Capability cap) const return false; case ApplicationState: return true; + case RasterGLSurface: + return true; default: return QPlatformIntegration::hasCapability(cap); } diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 777a3c12c5..80fba00ffb 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -119,7 +119,8 @@ void QIOSWindow::setVisible(bool visible) } if (visible && shouldAutoActivateWindow()) { - requestActivateWindow(); + if (!window()->property("_q_showWithoutActivating").toBool()) + requestActivateWindow(); } else if (!visible && [m_view isActiveWindow]) { // Our window was active/focus window but now hidden, so relinquish // focus to the next possible window in the stack. @@ -145,6 +146,9 @@ void QIOSWindow::setVisible(bool visible) bool QIOSWindow::shouldAutoActivateWindow() const { + if (![m_view canBecomeFirstResponder]) + return false; + // We don't want to do automatic window activation for popup windows // that are unlikely to contain editable controls (to avoid hiding // the keyboard while the popup is showing) diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 3039b89a1a..c6ef843b9f 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -77,7 +77,7 @@ if (QIOSIntegration::instance()->debugWindowManagement()) { static CGFloat hue = 0.0; CGFloat lastHue = hue; - for (CGFloat diff = 0; diff < 0.1 || diff > 0.9; diff = fabsf(hue - lastHue)) + for (CGFloat diff = 0; diff < 0.1 || diff > 0.9; diff = fabs(hue - lastHue)) hue = drand48(); #define colorWithBrightness(br) \ @@ -194,7 +194,7 @@ - (BOOL)canBecomeFirstResponder { - return YES; + return !(m_qioswindow->window()->flags() & Qt::WindowDoesNotAcceptFocus); } - (BOOL)becomeFirstResponder @@ -280,6 +280,12 @@ // ------------------------------------------------------------------------- +-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event +{ + if (m_qioswindow->window()->flags() & Qt::WindowTransparentForInput) + return NO; + return [super pointInside:point withEvent:event]; +} - (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state { diff --git a/src/plugins/platforms/kms/main.cpp b/src/plugins/platforms/kms/main.cpp index 8683a9c8d1..565ac7a7d4 100644 --- a/src/plugins/platforms/kms/main.cpp +++ b/src/plugins/platforms/kms/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QKmsIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "kms.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "kms.json") public: QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/linuxfb/main.cpp b/src/plugins/platforms/linuxfb/main.cpp index 046ee913d8..ba70984073 100644 --- a/src/plugins/platforms/linuxfb/main.cpp +++ b/src/plugins/platforms/linuxfb/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QLinuxFbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "linuxfb.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "linuxfb.json") public: QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/minimal/main.cpp b/src/plugins/platforms/minimal/main.cpp index 4c746a85f2..98babf6876 100644 --- a/src/plugins/platforms/minimal/main.cpp +++ b/src/plugins/platforms/minimal/main.cpp @@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE class QMinimalIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "minimal.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "minimal.json") public: QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/minimalegl/main.cpp b/src/plugins/platforms/minimalegl/main.cpp index 7ee14ae5ff..52ab3ad689 100644 --- a/src/plugins/platforms/minimalegl/main.cpp +++ b/src/plugins/platforms/minimalegl/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QMinimalEglIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "minimalegl.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "minimalegl.json") public: QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/offscreen/main.cpp b/src/plugins/platforms/offscreen/main.cpp index 64a0586036..363f2afcc3 100644 --- a/src/plugins/platforms/offscreen/main.cpp +++ b/src/plugins/platforms/offscreen/main.cpp @@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE class QOffscreenIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "offscreen.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "offscreen.json") public: QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/openwfd/main.cpp b/src/plugins/platforms/openwfd/main.cpp index d28ab945fa..b0403bc533 100644 --- a/src/plugins/platforms/openwfd/main.cpp +++ b/src/plugins/platforms/openwfd/main.cpp @@ -38,7 +38,7 @@ QT_BEGIN_NAMESPACE class QOpenWFDIntegrationPlugin : public QPlatformIntegrationPlugin { - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid) public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/qnx/main.h b/src/plugins/platforms/qnx/main.h index 5e69ee3889..955bef471c 100644 --- a/src/plugins/platforms/qnx/main.h +++ b/src/plugins/platforms/qnx/main.h @@ -38,7 +38,7 @@ QT_BEGIN_NAMESPACE class QQnxIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "qnx.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "qnx.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 99c44c69ef..5ed8d30e67 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -102,7 +102,7 @@ HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitName(/* [retval][out HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitVersion(/* [retval][out] */ BSTR *version) { - *version = ::SysAllocString(QT_UNICODE_LITERAL(QT_VERSION_STR)); + *version = ::SysAllocString(TEXT(QT_VERSION_STR)); return S_OK; } diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp index 5bdcbef01e..29bb9562e3 100644 --- a/src/plugins/platforms/windows/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -97,7 +97,7 @@ QT_BEGIN_NAMESPACE class QWindowsIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "windows.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "windows.json") public: QPlatformIntegration *create(const QString&, const QStringList&, int &, char **); }; diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 0184877fdd..06c9985cac 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -39,7 +39,6 @@ #include #if defined(QT_OPENGL_ES_2_ANGLE) || defined(QT_OPENGL_DYNAMIC) -# define EGL_EGLEXT_PROTOTYPES # include #endif @@ -137,7 +136,6 @@ bool QWindowsLibEGL::init() eglGetError = RESOLVE((EGLint (EGLAPIENTRY *)(void)), eglGetError); eglGetDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLNativeDisplayType)), eglGetDisplay); - eglGetPlatformDisplayEXT = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLenum platform, void *native_display, const EGLint *attrib_list)), eglGetPlatformDisplayEXT); eglInitialize = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLint *, EGLint *)), eglInitialize); eglTerminate = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay)), eglTerminate); eglChooseConfig = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)), eglChooseConfig); @@ -156,7 +154,15 @@ bool QWindowsLibEGL::init() eglSwapBuffers = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)), eglSwapBuffers); eglGetProcAddress = RESOLVE((__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * )(const char *)), eglGetProcAddress); - return eglGetError && eglGetDisplay && eglInitialize; + if (!eglGetError || !eglGetDisplay || !eglInitialize || !eglGetProcAddress) + return false; + + eglGetPlatformDisplayEXT = 0; +#ifdef EGL_ANGLE_platform_angle + eglGetPlatformDisplayEXT = reinterpret_cast(eglGetProcAddress("eglGetPlatformDisplayEXT")); +#endif + + return true; } #if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC) @@ -360,7 +366,7 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: EGLDisplay display = EGL_NO_DISPLAY; EGLint major = 0; EGLint minor = 0; -#ifdef EGL_ANGLE_platform_angle_opengl +#ifdef EGL_ANGLE_platform_angle if (libEGL.eglGetPlatformDisplayEXT && (preferredType & QWindowsOpenGLTester::AngleBackendMask)) { const EGLint anglePlatformAttributes[][5] = { @@ -384,7 +390,7 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: } } } -#else // EGL_ANGLE_platform_angle_opengl +#else // EGL_ANGLE_platform_angle Q_UNUSED(preferredType) #endif if (display == EGL_NO_DISPLAY) diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index 2b249348c3..d8302c97a7 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -46,7 +46,6 @@ struct QWindowsLibEGL EGLint (EGLAPIENTRY * eglGetError)(void); EGLDisplay (EGLAPIENTRY * eglGetDisplay)(EGLNativeDisplayType display_id); - EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list); EGLBoolean (EGLAPIENTRY * eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); EGLBoolean (EGLAPIENTRY * eglTerminate)(EGLDisplay dpy); EGLBoolean (EGLAPIENTRY * eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, @@ -74,6 +73,8 @@ struct QWindowsLibEGL EGLBoolean (EGLAPIENTRY * eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); __eglMustCastToProperFunctionPointerType (EGLAPIENTRY * eglGetProcAddress)(const char *procname); + EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list); + private: #if !defined(QT_STATIC) || defined(QT_OPENGL_DYNAMIC) void *resolve(const char *name); diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index 9691156403..6e58c55bbe 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -34,6 +34,7 @@ #include "qwindowsnativeinterface.h" #include "qwindowswindow.h" #include "qwindowscontext.h" +#include "qwindowsfontdatabase.h" #include "qwindowsopenglcontext.h" #include "qwindowsopengltester.h" #include "qwindowsintegration.h" @@ -222,6 +223,11 @@ int QWindowsNativeInterface::registerMimeType(const QString &mimeType) return QWindowsMime::registerMimeType(mimeType); } +QFont QWindowsNativeInterface::logFontToQFont(const void *logFont, int verticalDpi) +{ + return QWindowsFontDatabase::LOGFONT_to_QFont(*reinterpret_cast(logFont), verticalDpi); +} + QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &function) const { if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier()) diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h index be8418b769..97839ae1ae 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -34,6 +34,7 @@ #ifndef QWINDOWSNATIVEINTERFACE_H #define QWINDOWSNATIVEINTERFACE_H +#include #include QT_BEGIN_NAMESPACE @@ -77,6 +78,7 @@ public: Q_INVOKABLE void registerWindowsMime(void *mimeIn); Q_INVOKABLE void unregisterWindowsMime(void *mime); Q_INVOKABLE int registerMimeType(const QString &mimeType); + Q_INVOKABLE QFont logFontToQFont(const void *logFont, int verticalDpi); bool asyncExpose() const; void setAsyncExpose(bool value); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 923040fd71..543c08135f 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -438,6 +438,8 @@ QDebug operator<<(QDebug debug, const WindowCreationData &d) // Fix top level window flags in case only the type flags are passed. static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags) { + // Not supported on Windows, also do correction when it is set. + flags &= ~Qt::WindowFullscreenButtonHint; switch (flags) { case Qt::Window: flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint diff --git a/src/plugins/platforms/winrt/main.cpp b/src/plugins/platforms/winrt/main.cpp index 1398c52e96..d1cf08887f 100644 --- a/src/plugins/platforms/winrt/main.cpp +++ b/src/plugins/platforms/winrt/main.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -40,7 +43,7 @@ QT_BEGIN_NAMESPACE class QWinRTIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "winrt.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "winrt.json") public: QStringList keys() const; diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp index b55551e820..dcf8239538 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.h b/src/plugins/platforms/winrt/qwinrtbackingstore.h index 69bd3c397c..20b27a3865 100644 --- a/src/plugins/platforms/winrt/qwinrtbackingstore.h +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index 1adb2bb89f..94ce23bd2c 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -46,7 +49,7 @@ using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::Foundation; -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE class QWinRTCursorPrivate { @@ -155,3 +158,6 @@ QPoint QWinRTCursor::pos() const coreWindow->get_PointerPosition(&point); return QPoint(point.X, point.Y); } + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/winrt/qwinrtcursor.h b/src/plugins/platforms/winrt/qwinrtcursor.h index 4245faab6f..9c9b9e93ef 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.h +++ b/src/plugins/platforms/winrt/qwinrtcursor.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -36,7 +39,7 @@ #include -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE class QWinRTCursorPrivate; class QWinRTCursor : public QPlatformCursor @@ -54,4 +57,6 @@ private: Q_DECLARE_PRIVATE(QWinRTCursor) }; +QT_END_NAMESPACE + #endif // QWINRTCURSOR_H diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index fd90582119..42ffe8f716 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -33,6 +36,9 @@ #include "qwinrteglcontext.h" +#define EGL_EGLEXT_PROTOTYPES +#include "EGL/eglext.h" + QT_BEGIN_NAMESPACE QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config) @@ -40,6 +46,17 @@ QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGL { } +void QWinRTEGLContext::swapBuffers(QPlatformSurface *surface) +{ +#ifdef Q_OS_WINPHONE + const QSize size = surface->surface()->size(); + eglPostSubBufferNV(eglDisplay(), eglSurfaceForPlatformSurface(surface), + 0, 0, size.width(), size.height()); +#else + eglSwapBuffers(eglDisplay(), eglSurfaceForPlatformSurface(surface)); +#endif +} + EGLSurface QWinRTEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { if (surface->surface()->surfaceClass() == QSurface::Window) { diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index bec9c19089..958d623c4c 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -43,6 +46,7 @@ class QWinRTEGLContext : public QEGLPlatformContext public: explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config); + void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; protected: diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp index 7f77b79660..716681c905 100644 --- a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp +++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.h b/src/plugins/platforms/winrt/qwinrteventdispatcher.h index 35e637eba5..ecbdde34bd 100644 --- a/src/plugins/platforms/winrt/qwinrteventdispatcher.h +++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp index 417befeb63..e1b2a07d5f 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h index 13abf6e2b8..51b79c84ef 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp index 719bb18dd6..858cb841b9 100644 --- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp +++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.h b/src/plugins/platforms/winrt/qwinrtfileengine.h index 983338f2e2..86721d8578 100644 --- a/src/plugins/platforms/winrt/qwinrtfileengine.h +++ b/src/plugins/platforms/winrt/qwinrtfileengine.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -36,8 +39,6 @@ #include -QT_BEGIN_NAMESPACE - namespace ABI { namespace Windows { namespace Storage { @@ -46,6 +47,8 @@ namespace ABI { } } +QT_BEGIN_NAMESPACE + class QWinRTFileEngineHandlerPrivate; class QWinRTFileEngineHandler : public QAbstractFileEngineHandler { diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp index 15767c2805..09edea52e7 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -46,6 +49,71 @@ using namespace Microsoft::WRL; QT_BEGIN_NAMESPACE +// Based on unicode range tables at http://www.microsoft.com/typography/otspec/os2.htm#ur +static QFontDatabase::WritingSystem writingSystemFromUnicodeRange(const DWRITE_UNICODE_RANGE &range) +{ + if (range.first >= 0x0000 && range.last <= 0x007F) + return QFontDatabase::Latin; + if (range.first >= 0x0370 && range.last <= 0x03FF) + return QFontDatabase::Greek; + if (range.first >= 0x0400 && range.last <= 0x04FF) + return QFontDatabase::Cyrillic; + if (range.first >= 0x0530 && range.last <= 0x058F) + return QFontDatabase::Armenian; + if (range.first >= 0x0590 && range.last <= 0x05FF) + return QFontDatabase::Hebrew; + if (range.first >= 0x0600 && range.last <= 0x06FF) + return QFontDatabase::Arabic; + if (range.first >= 0x0700 && range.last <= 0x074F) + return QFontDatabase::Syriac; + if (range.first >= 0x0780 && range.last <= 0x07BF) + return QFontDatabase::Thaana; + if (range.first >= 0x0900 && range.last <= 0x097F) + return QFontDatabase::Devanagari; + if (range.first >= 0x0980 && range.last <= 0x09FF) + return QFontDatabase::Bengali; + if (range.first >= 0x0A00 && range.last <= 0x0A7F) + return QFontDatabase::Gurmukhi; + if (range.first >= 0x0A80 && range.last <= 0x0AFF) + return QFontDatabase::Gujarati; + if (range.first >= 0x0B00 && range.last <= 0x0B7F) + return QFontDatabase::Oriya; + if (range.first >= 0x0B80 && range.last <= 0x0BFF) + return QFontDatabase::Tamil; + if (range.first >= 0x0C00 && range.last <= 0x0C7F) + return QFontDatabase::Telugu; + if (range.first >= 0x0C80 && range.last <= 0x0CFF) + return QFontDatabase::Kannada; + if (range.first >= 0x0D00 && range.last <= 0x0D7F) + return QFontDatabase::Malayalam; + if (range.first >= 0x0D80 && range.last <= 0x0DFF) + return QFontDatabase::Sinhala; + if (range.first >= 0x0E00 && range.last <= 0x0E7F) + return QFontDatabase::Thai; + if (range.first >= 0x0E80 && range.last <= 0x0EFF) + return QFontDatabase::Lao; + if (range.first >= 0x0F00 && range.last <= 0x0FFF) + return QFontDatabase::Tibetan; + if (range.first >= 0x1000 && range.last <= 0x109F) + return QFontDatabase::Myanmar; + if (range.first >= 0x10A0 && range.last <= 0x10FF) + return QFontDatabase::Georgian; + if (range.first >= 0x1780 && range.last <= 0x17FF) + return QFontDatabase::Khmer; + if (range.first >= 0x4E00 && range.last <= 0x9FFF) + return QFontDatabase::SimplifiedChinese; + if (range.first >= 0xAC00 && range.last <= 0xD7AF) + return QFontDatabase::Korean; + if (range.first >= 0x1680 && range.last <= 0x169F) + return QFontDatabase::Ogham; + if (range.first >= 0x16A0 && range.last <= 0x16FF) + return QFontDatabase::Runic; + if (range.first >= 0x07C0 && range.last <= 0x07FF) + return QFontDatabase::Nko; + + return QFontDatabase::Other; +} + QString QWinRTFontDatabase::fontDir() const { QString fontDirectory = QBasicFontDatabase::fontDir(); @@ -260,17 +328,27 @@ void QWinRTFontDatabase::populateFamily(const QString &familyName) const bool fixedPitch = fontFace->IsMonospacedFont(); - quint32 unicodeRange[4]; + // Get writing systems from unicode ranges quint32 actualRangeCount; - hr = fontFace->GetUnicodeRanges( - 2, reinterpret_cast(unicodeRange), &actualRangeCount); - if (FAILED(hr) && hr != E_NOT_SUFFICIENT_BUFFER) { // Ignore insufficient buffer; we only need 4 indices + hr = fontFace->GetUnicodeRanges(0, nullptr, &actualRangeCount); + Q_ASSERT(hr == E_NOT_SUFFICIENT_BUFFER); + QVector unicodeRanges(actualRangeCount); + hr = fontFace->GetUnicodeRanges(actualRangeCount, unicodeRanges.data(), &actualRangeCount); + if (FAILED(hr)) { qWarning("Unable to get font unicode range: %s", qPrintable(qt_error_string(hr))); continue; } - quint32 codePageRange[2] = { 0, 0 }; - QSupportedWritingSystems writingSystems = - QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + QSupportedWritingSystems writingSystems; + for (quint32 i = 0; i < actualRangeCount; ++i) { + const QFontDatabase::WritingSystem writingSystem = writingSystemFromUnicodeRange(unicodeRanges.at(i)); + writingSystems.setSupported(writingSystem); + } + if (writingSystems.supported(QFontDatabase::SimplifiedChinese)) { + writingSystems.setSupported(QFontDatabase::TraditionalChinese); + writingSystems.setSupported(QFontDatabase::Japanese); + } + if (writingSystems.supported(QFontDatabase::Latin)) + writingSystems.setSupported(QFontDatabase::Vietnamese); IDWriteFontFile *fontFile; hr = fontFace->GetFiles(&fileCount, &fontFile); diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.h b/src/plugins/platforms/winrt/qwinrtfontdatabase.h index cde81baa44..7b3f402c13 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.h +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -36,12 +39,14 @@ #include -QT_BEGIN_NAMESPACE - #ifdef QT_WINRT_USE_DWRITE struct IDWriteFontFile; struct IDWriteFontFamily; +#endif +QT_BEGIN_NAMESPACE + +#ifdef QT_WINRT_USE_DWRITE struct FontDescription { quint32 index; diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index f0de578db6..c94b53ef1c 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.h b/src/plugins/platforms/winrt/qwinrtinputcontext.h index 761908a9cb..ce7fbabf49 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.h +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 015ebaadb5..70ee6dbe6a 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h index 1ec44cd46a..bbd6c1e41b 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp index c5d3634523..4fc1fea626 100644 --- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h index fc510fe34e..2f473a05f7 100644 --- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index c4512b4d2d..1d36bb31f6 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index cbef9543a9..d34ce75748 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp index 1faa3945a7..cb04f670d2 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.cpp +++ b/src/plugins/platforms/winrt/qwinrtservices.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtservices.h b/src/plugins/platforms/winrt/qwinrtservices.h index 0262a2ab83..585eb2f010 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.h +++ b/src/plugins/platforms/winrt/qwinrtservices.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** @@ -37,7 +40,7 @@ #include #include -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE class QWinRTServicesPrivate; class QWinRTServices : public QPlatformServices @@ -54,4 +57,6 @@ private: Q_DECLARE_PRIVATE(QWinRTServices) }; +QT_END_NAMESPACE + #endif // QWINRTSERVICES_H diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp index c42368cc87..a0fa2798a8 100644 --- a/src/plugins/platforms/winrt/qwinrttheme.cpp +++ b/src/plugins/platforms/winrt/qwinrttheme.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrttheme.h b/src/plugins/platforms/winrt/qwinrttheme.h index 73dcd6cdf4..2e159cbd55 100644 --- a/src/plugins/platforms/winrt/qwinrttheme.h +++ b/src/plugins/platforms/winrt/qwinrttheme.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index b96f4255c2..adc5dfb776 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index eee95d6bd3..3cfe346ab2 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -5,7 +5,7 @@ ** ** This file is part of the plugins of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -16,16 +16,19 @@ ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later 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 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro b/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro index 29b6d1d2f7..9de0476810 100644 --- a/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro +++ b/src/plugins/platforms/xcb/gl_integrations/gl_integrations.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -contains(QT_CONFIG, egl):contains(QT_CONFIG, egl_x11) { +contains(QT_CONFIG, egl): contains(QT_CONFIG, egl_x11): contains(QT_CONFIG, opengl) { SUBDIRS += xcb_egl } diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h index c71c668f31..74c117582a 100644 --- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h +++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h @@ -57,7 +57,9 @@ public: virtual bool handleXcbEvent(xcb_generic_event_t *event, uint responseType); virtual QXcbWindow *createWindow(QWindow *window) const = 0; +#ifndef QT_NO_OPENGL virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const = 0; +#endif virtual QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const = 0; virtual QXcbNativeInterfaceHandler *nativeInterfaceHandler() const { return Q_NULLPTR; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 5d32eb7614..78282d1415 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -70,7 +70,6 @@ #endif #if defined(XCB_USE_XINPUT2) -#include #include #endif @@ -457,6 +456,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra , m_focusWindow(0) , m_systemTrayTracker(0) , m_glIntegration(Q_NULLPTR) + , m_xiGrab(false) { #ifdef XCB_USE_XLIB Display *dpy = XOpenDisplay(m_displayName.constData()); @@ -909,7 +909,7 @@ static Qt::MouseButtons translateMouseButtons(int s) return ret; } -static Qt::MouseButton translateMouseButton(xcb_button_t s) +Qt::MouseButton QXcbConnection::translateMouseButton(xcb_button_t s) { switch (s) { case 1: return Qt::LeftButton; @@ -944,39 +944,6 @@ static Qt::MouseButton translateMouseButton(xcb_button_t s) } } -void QXcbConnection::handleButtonPress(xcb_generic_event_t *ev) -{ - xcb_button_press_event_t *event = (xcb_button_press_event_t *)ev; - - // the event explicitly contains the state of the three first buttons, - // the rest we need to manage ourselves - m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state); - m_buttons |= translateMouseButton(event->detail); - qCDebug(lcQpaXInput, "xcb: pressed mouse button %d, button state %X", event->detail, static_cast(m_buttons)); -} - -void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev) -{ - xcb_button_release_event_t *event = (xcb_button_release_event_t *)ev; - - // the event explicitly contains the state of the three first buttons, - // the rest we need to manage ourselves - m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state); - m_buttons &= ~translateMouseButton(event->detail); - qCDebug(lcQpaXInput, "xcb: released mouse button %d, button state %X", event->detail, static_cast(m_buttons)); -} - -void QXcbConnection::handleMotionNotify(xcb_generic_event_t *ev) -{ - xcb_motion_notify_event_t *event = (xcb_motion_notify_event_t *)ev; - - m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state); -#ifdef Q_XCB_DEBUG - qCDebug(lcQpaXInput, "xcb: moved mouse to %4d, %4d; button state %X", - event->event_x, event->event_y, static_cast(m_buttons)); -#endif -} - #ifndef QT_NO_XKB namespace { typedef union { @@ -1018,18 +985,35 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) switch (response_type) { case XCB_EXPOSE: HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); - case XCB_BUTTON_PRESS: - m_keyboard->updateXKBStateFromCore(((xcb_button_press_event_t *)event)->state); - handleButtonPress(event); + + // press/release/motion is only delivered here when XI 2.2+ is _not_ in use + case XCB_BUTTON_PRESS: { + xcb_button_press_event_t *ev = (xcb_button_press_event_t *)event; + m_keyboard->updateXKBStateFromCore(ev->state); + // the event explicitly contains the state of the three first buttons, + // the rest we need to manage ourselves + m_buttons = (m_buttons & ~0x7) | translateMouseButtons(ev->state); + m_buttons |= translateMouseButton(ev->detail); + qCDebug(lcQpaXInput, "legacy mouse press, button %d state %X", ev->detail, static_cast(m_buttons)); HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); - case XCB_BUTTON_RELEASE: - m_keyboard->updateXKBStateFromCore(((xcb_button_release_event_t *)event)->state); - handleButtonRelease(event); + } + case XCB_BUTTON_RELEASE: { + xcb_button_release_event_t *ev = (xcb_button_release_event_t *)event; + m_keyboard->updateXKBStateFromCore(ev->state); + m_buttons = (m_buttons & ~0x7) | translateMouseButtons(ev->state); + m_buttons &= ~translateMouseButton(ev->detail); + qCDebug(lcQpaXInput, "legacy mouse release, button %d state %X", ev->detail, static_cast(m_buttons)); HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); - case XCB_MOTION_NOTIFY: - m_keyboard->updateXKBStateFromCore(((xcb_motion_notify_event_t *)event)->state); - handleMotionNotify(event); + } + case XCB_MOTION_NOTIFY: { + xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)event; + m_keyboard->updateXKBStateFromCore(ev->state); + m_buttons = (m_buttons & ~0x7) | translateMouseButtons(ev->state); + qCDebug(lcQpaXInput, "legacy mouse move %d,%d button %d state %X", ev->event_x, ev->event_y, + ev->detail, static_cast(m_buttons)); HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); + } + case XCB_CONFIGURE_NOTIFY: HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); case XCB_MAP_NOTIFY: @@ -1090,6 +1074,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) break; #if defined(XCB_USE_XINPUT2) case XCB_GE_GENERIC: + // Here the windowEventListener is invoked from xi2HandleEvent() if (m_xi2Enabled) xi2HandleEvent(reinterpret_cast(event)); break; @@ -1931,6 +1916,12 @@ void QXcbConnection::initializeXKB() #endif } +bool QXcbConnection::xi2MouseEvents() const +{ + static bool mouseViaXI2 = !qEnvironmentVariableIsSet("QT_XCB_NO_XI2_MOUSE"); + return mouseViaXI2; +} + #if defined(XCB_USE_XINPUT2) static int xi2ValuatorOffset(unsigned char *maskPtr, int maskLen, int number) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 466492ce42..0191b0e1ef 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -69,7 +69,8 @@ #endif #endif struct XInput2TouchDeviceData; -#endif +#endif // XCB_USE_XINPUT2 + struct xcb_randr_get_output_info_reply_t; //#define Q_XCB_DEBUG @@ -347,6 +348,7 @@ public: virtual void handleFocusInEvent(const xcb_focus_in_event_t *) {} virtual void handleFocusOutEvent(const xcb_focus_out_event_t *) {} virtual void handlePropertyNotifyEvent(const xcb_property_notify_event_t *) {} + virtual void handleXIMouseEvent(xcb_ge_event_t *) {} virtual QXcbWindow *toWindow() { return 0; } }; @@ -413,14 +415,14 @@ public: void xi2Select(xcb_window_t window); #endif #ifdef XCB_USE_XINPUT21 - bool isUsingXInput21() const { return m_xi2Enabled && m_xi2Minor >= 1; } + bool isAtLeastXI21() const { return m_xi2Enabled && m_xi2Minor >= 1; } #else - bool isUsingXInput21() const { return false; } + bool isAtLeastXI21() const { return false; } #endif #ifdef XCB_USE_XINPUT22 - bool isUsingXInput22() const { return m_xi2Enabled && m_xi2Minor >= 2; } + bool isAtLeastXI22() const { return m_xi2Enabled && m_xi2Minor >= 2; } #else - bool isUsingXInput22() const { return false; } + bool isAtLeastXI22() const { return false; } #endif void sync(); @@ -457,7 +459,9 @@ public: xcb_timestamp_t getTimestamp(); + void setButton(Qt::MouseButton button, bool down) { if (down) m_buttons |= button; else m_buttons &= ~button; } Qt::MouseButtons buttons() const { return m_buttons; } + Qt::MouseButton translateMouseButton(xcb_button_t s); QXcbWindow *focusWindow() const { return m_focusWindow; } void setFocusWindow(QXcbWindow *); @@ -479,12 +483,19 @@ public: void handleEnterEvent(const xcb_enter_notify_event_t *); #endif +#ifdef XCB_USE_XINPUT22 + bool xi2SetMouseGrabEnabled(xcb_window_t w, bool grab); +#endif + Qt::MouseButton xiToQtMouseButton(uint32_t b); + QXcbEventReader *eventReader() const { return m_reader; } bool canGrab() const { return m_canGrabServer; } QXcbGlIntegration *glIntegration() const { return m_glIntegration; } + bool xi2MouseEvents() const; + protected: bool event(QEvent *e) Q_DECL_OVERRIDE; @@ -512,9 +523,6 @@ private: bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output); void initializeScreens(); void updateScreens(const xcb_randr_notify_event_t *event); - void handleButtonPress(xcb_generic_event_t *event); - void handleButtonRelease(xcb_generic_event_t *event); - void handleMotionNotify(xcb_generic_event_t *event); bool m_xi2Enabled; int m_xi2Minor; @@ -527,6 +535,9 @@ private: void xi2HandleHierachyEvent(void *event); void xi2HandleDeviceChangedEvent(void *event); int m_xiOpCode, m_xiEventBase, m_xiErrorBase; +#ifdef XCB_USE_XINPUT22 + void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow); +#endif // XCB_USE_XINPUT22 #ifndef QT_NO_TABLETEVENT struct TabletData { TabletData() : deviceId(0), pointerType(QTabletEvent::UnknownPointer), @@ -546,10 +557,10 @@ private: }; QHash valuatorInfo; }; - bool xi2HandleTabletEvent(void *event, TabletData *tabletData); + bool xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener); void xi2ReportTabletEvent(TabletData &tabletData, void *event); QVector m_tabletData; -#endif +#endif // !QT_NO_TABLETEVENT struct ScrollingDevice { ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { } int deviceId; @@ -562,9 +573,7 @@ private: void updateScrollingDevice(ScrollingDevice& scrollingDevice, int num_classes, void *classes); void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice); QHash m_scrollingDevices; -#endif // XCB_USE_XINPUT2 -#if defined(XCB_USE_XINPUT2) static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value); static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode); #endif @@ -636,6 +645,7 @@ private: QByteArray m_startupId; QXcbSystemTrayTracker *m_systemTrayTracker; QXcbGlIntegration *m_glIntegration; + bool m_xiGrab; friend class QXcbEventReader; }; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index d1b3ead11c..c7784ddb48 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -43,7 +43,6 @@ #include #include -#define FINGER_MAX_WIDTH_MM 10 struct XInput2TouchDeviceData { XInput2TouchDeviceData() @@ -175,9 +174,11 @@ void QXcbConnection::xi2SetupDevices() case XIKeyClass: qCDebug(lcQpaXInputDevices) << " it's a keyboard"; break; +#ifdef XCB_USE_XINPUT22 case XITouchClass: // will be handled in deviceForId() break; +#endif default: qCDebug(lcQpaXInputDevices) << " has class" << devices[i].classes[c]->type; break; @@ -274,34 +275,37 @@ void QXcbConnection::xi2Select(xcb_window_t window) unsigned char *xiBitMask = reinterpret_cast(&bitMask); #ifdef XCB_USE_XINPUT22 - if (isUsingXInput22()) { + if (isAtLeastXI22()) { bitMask |= XI_TouchBeginMask; bitMask |= XI_TouchUpdateMask; bitMask |= XI_TouchEndMask; + bitMask |= XI_PropertyEventMask; // for tablets + if (xi2MouseEvents()) { + // We want both mouse and touch through XI2 if touch is supported (>= 2.2). + // The plain xcb press and motion events will not be delivered after this. + bitMask |= XI_ButtonPressMask; + bitMask |= XI_ButtonReleaseMask; + bitMask |= XI_MotionMask; + qCDebug(lcQpaXInput, "XInput 2.2: Selecting press/release/motion events in addition to touch"); + } XIEventMask mask; mask.mask_len = sizeof(bitMask); mask.mask = xiBitMask; - if (!m_touchDevices.isEmpty()) { - // If we select for touch events on the master pointer, XInput2 - // will not synthesize mouse events. This means Qt must do it, - // which is also preferable, since Qt can control better when - // to do so. - mask.deviceid = XIAllMasterDevices; - Status result = XISelectEvents(xDisplay, window, &mask, 1); - if (result != Success) - qCDebug(lcQpaXInput, "XInput 2.2: failed to select touch events, window %x, result %d", window, result); - } + // When xi2MouseEvents() is true (the default), pointer emulation for touch and tablet + // events will get disabled. This is preferable for touch, as Qt Quick handles touch events + // directly while for others QtGui synthesizes mouse events, not so much for tablets. For + // the latter we will synthesize the events ourselves. + mask.deviceid = XIAllMasterDevices; + Status result = XISelectEvents(xDisplay, window, &mask, 1); + if (result != Success) + qCDebug(lcQpaXInput, "XInput 2.2: failed to select pointer/touch events, window %x, result %d", window, result); } #endif // XCB_USE_XINPUT22 + const bool pointerSelected = isAtLeastXI22() && xi2MouseEvents(); QSet tabletDevices; #ifndef QT_NO_TABLETEVENT - // For each tablet, select some additional event types. - // Press, motion, etc. events must never be selected for _all_ devices - // as that would render the standard XCB_MOTION_NOTIFY and - // similar handlers useless and we have no intention to infect - // all the pure xcb code with Xlib-based XI2. - if (!m_tabletData.isEmpty()) { + if (!m_tabletData.isEmpty() && !pointerSelected) { unsigned int tabletBitMask; unsigned char *xiTabletBitMask = reinterpret_cast(&tabletBitMask); QVector xiEventMask(m_tabletData.count()); @@ -322,7 +326,8 @@ void QXcbConnection::xi2Select(xcb_window_t window) #ifdef XCB_USE_XINPUT21 // Enable each scroll device - if (!m_scrollingDevices.isEmpty()) { + if (!m_scrollingDevices.isEmpty() && !pointerSelected) { + // Only when XI2 mouse events are not enabled, otherwise motion and release are selected already. QVector xiEventMask(m_scrollingDevices.size()); unsigned int scrollBitMask; unsigned char *xiScrollBitMask = reinterpret_cast(&scrollBitMask); @@ -359,8 +364,8 @@ void QXcbConnection::xi2Select(xcb_window_t window) XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) { XInput2TouchDeviceData *dev = Q_NULLPTR; - QHash::const_iterator devIt = m_touchDevices.find(id); - if ( devIt != m_touchDevices.end() ) { + QHash::const_iterator devIt = m_touchDevices.constFind(id); + if (devIt != m_touchDevices.cend()) { dev = devIt.value(); } else { int nrDevices = 0; @@ -424,7 +429,7 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) dev->size.width() > 10000 || dev->size.height() > 10000) dev->size = QSizeF(130, 110); } - if (!isUsingXInput22() || type == QTouchDevice::TouchPad) + if (!isAtLeastXI22() || type == QTouchDevice::TouchPad) caps |= QTouchDevice::MouseEmulation; if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) { @@ -446,9 +451,9 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) } #if defined(XCB_USE_XINPUT21) || !defined(QT_NO_TABLETEVENT) -static qreal fixed1616ToReal(FP1616 val) +static inline qreal fixed1616ToReal(FP1616 val) { - return (qreal(val >> 16)) + (val & 0xFFFF) / (qreal)0xFFFF; + return qreal(val) / 0x10000; } #endif // defined(XCB_USE_XINPUT21) || !defined(QT_NO_TABLETEVENT) @@ -467,163 +472,280 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { if (xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) { xXIGenericDeviceEvent *xiEvent = reinterpret_cast(event); + int sourceDeviceId = xiEvent->deviceid; // may be the master id + xXIDeviceEvent *xiDeviceEvent = 0; + QXcbWindowEventListener *eventListener = 0; - if (xiEvent->evtype == XI_HierarchyChanged) { + switch (xiEvent->evtype) { + case XI_ButtonPress: + case XI_ButtonRelease: + case XI_Motion: + case XI_TouchBegin: + case XI_TouchUpdate: + case XI_TouchEnd: + { + xiDeviceEvent = reinterpret_cast(event); + eventListener = windowEventListenerFromId(xiDeviceEvent->event); + if (eventListener) { + long result = 0; + if (eventListener->handleGenericEvent(reinterpret_cast(event), &result)) + return; + } + sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master + break; + } + case XI_HierarchyChanged: xi2HandleHierachyEvent(xiEvent); return; - } - if (xiEvent->evtype == XI_DeviceChanged) { + case XI_DeviceChanged: xi2HandleDeviceChangedEvent(xiEvent); return; + default: + break; } #ifndef QT_NO_TABLETEVENT for (int i = 0; i < m_tabletData.count(); ++i) { - if (m_tabletData.at(i).deviceId == xiEvent->deviceid) { - if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i])) + if (m_tabletData.at(i).deviceId == sourceDeviceId) { + if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i], eventListener)) return; } } #endif // QT_NO_TABLETEVENT #ifdef XCB_USE_XINPUT21 - QHash::iterator device = m_scrollingDevices.find(xiEvent->deviceid); + QHash::iterator device = m_scrollingDevices.find(sourceDeviceId); if (device != m_scrollingDevices.end()) xi2HandleScrollEvent(xiEvent, device.value()); #endif // XCB_USE_XINPUT21 #ifdef XCB_USE_XINPUT22 - if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) { - xXIDeviceEvent* xiDeviceEvent = reinterpret_cast(event); - if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) - qCDebug(lcQpaXInput, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f", - event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail, - fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), - fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) ); - - if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { - XInput2TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid); - Q_ASSERT(dev); - const bool firstTouch = m_touchPoints.isEmpty(); - if (xiEvent->evtype == XI_TouchBegin) { - QWindowSystemInterface::TouchPoint tp; - tp.id = xiDeviceEvent->detail % INT_MAX; - tp.state = Qt::TouchPointPressed; - tp.pressure = -1.0; - m_touchPoints[tp.id] = tp; - } - QWindowSystemInterface::TouchPoint &touchPoint = m_touchPoints[xiDeviceEvent->detail]; - qreal x = fixed1616ToReal(xiDeviceEvent->root_x); - qreal y = fixed1616ToReal(xiDeviceEvent->root_y); - qreal nx = -1.0, ny = -1.0, w = 0.0, h = 0.0; - QXcbScreen* screen = m_screens.at(0); - for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { - XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; - if (classinfo->type == XIValuatorClass) { - XIValuatorClassInfo *vci = reinterpret_cast(classinfo); - int n = vci->number; - double value; - if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value)) - continue; - if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) - qCDebug(lcQpaXInput, " valuator %20s value %lf from range %lf -> %lf", - atomName(vci->label).constData(), value, vci->min, vci->max ); - if (vci->label == atom(QXcbAtom::RelX)) { - nx = valuatorNormalized(value, vci); - } else if (vci->label == atom(QXcbAtom::RelY)) { - ny = valuatorNormalized(value, vci); - } else if (vci->label == atom(QXcbAtom::AbsX)) { - nx = valuatorNormalized(value, vci); - } else if (vci->label == atom(QXcbAtom::AbsY)) { - ny = valuatorNormalized(value, vci); - } else if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { - nx = valuatorNormalized(value, vci); - } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { - ny = valuatorNormalized(value, vci); - } else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) { - // Convert the value within its range as a fraction of a finger's max (contact patch) - // width in mm, and from there to pixels depending on screen resolution - w = valuatorNormalized(value, vci) * FINGER_MAX_WIDTH_MM * - screen->geometry().width() / screen->physicalSize().width(); - } else if (vci->label == atom(QXcbAtom::AbsMTTouchMinor)) { - h = valuatorNormalized(value, vci) * FINGER_MAX_WIDTH_MM * - screen->geometry().height() / screen->physicalSize().height(); - } else if (vci->label == atom(QXcbAtom::AbsMTPressure) || - vci->label == atom(QXcbAtom::AbsPressure)) { - touchPoint.pressure = valuatorNormalized(value, vci); - } - } - } - // If any value was not updated, use the last-known value. - if (nx == -1.0) { - x = touchPoint.area.center().x(); - nx = x / screen->geometry().width(); - } - if (ny == -1.0) { - y = touchPoint.area.center().y(); - ny = y / screen->geometry().height(); - } - if (xiEvent->evtype != XI_TouchEnd) { - if (w == 0.0) - w = touchPoint.area.width(); - if (h == 0.0) - h = touchPoint.area.height(); - } - - switch (xiEvent->evtype) { - case XI_TouchBegin: - if (firstTouch) { - dev->firstPressedPosition = QPointF(x, y); - dev->firstPressedNormalPosition = QPointF(nx, ny); - } - dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y)); - break; - case XI_TouchUpdate: - if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { - qreal dx = (nx - dev->firstPressedNormalPosition.x()) * - dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); - qreal dy = (ny - dev->firstPressedNormalPosition.y()) * - dev->size.height() * screen->geometry().height() / screen->physicalSize().height(); - x = dev->firstPressedPosition.x() + dx; - y = dev->firstPressedPosition.y() + dy; - touchPoint.state = Qt::TouchPointMoved; - } else if (touchPoint.area.center() != QPoint(x, y)) { - touchPoint.state = Qt::TouchPointMoved; - dev->pointPressedPosition[touchPoint.id] = QPointF(x, y); - } - break; - case XI_TouchEnd: - touchPoint.state = Qt::TouchPointReleased; - if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { - qreal dx = (nx - dev->firstPressedNormalPosition.x()) * - dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); - qreal dy = (ny - dev->firstPressedNormalPosition.y()) * - dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); - x = dev->firstPressedPosition.x() + dx; - y = dev->firstPressedPosition.y() + dy; - } - dev->pointPressedPosition.remove(touchPoint.id); - } - touchPoint.area = QRectF(x - w/2, y - h/2, w, h); - touchPoint.normalPosition = QPointF(nx, ny); + if (xiDeviceEvent) { + switch (xiDeviceEvent->evtype) { + case XI_ButtonPress: + case XI_ButtonRelease: + case XI_Motion: + if (xi2MouseEvents() && eventListener) + eventListener->handleXIMouseEvent(event); + break; + case XI_TouchBegin: + case XI_TouchUpdate: + case XI_TouchEnd: if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) - qCDebug(lcQpaXInput) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << - " area " << touchPoint.area << " pressure " << touchPoint.pressure; - QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiEvent->time, dev->qtTouchDevice, m_touchPoints.values()); - if (touchPoint.state == Qt::TouchPointReleased) - // If a touchpoint was released, we can forget it, because the ID won't be reused. - m_touchPoints.remove(touchPoint.id); - else - // Make sure that we don't send TouchPointPressed/Moved in more than one QTouchEvent - // with this touch point if the next XI2 event is about a different touch point. - touchPoint.state = Qt::TouchPointStationary; + qCDebug(lcQpaXInput, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x", + event->event_type, xiDeviceEvent->sequenceNumber, xiDeviceEvent->detail, + fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), + fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event); + if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) + xi2ProcessTouch(xiDeviceEvent, platformWindow); + break; } } #endif // XCB_USE_XINPUT22 } } +#ifdef XCB_USE_XINPUT22 +void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow) +{ + xXIDeviceEvent *xiDeviceEvent = static_cast(xiDevEvent); + XInput2TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid); + Q_ASSERT(dev); + const bool firstTouch = m_touchPoints.isEmpty(); + if (xiDeviceEvent->evtype == XI_TouchBegin) { + QWindowSystemInterface::TouchPoint tp; + tp.id = xiDeviceEvent->detail % INT_MAX; + tp.state = Qt::TouchPointPressed; + tp.pressure = -1.0; + m_touchPoints[tp.id] = tp; + } + QWindowSystemInterface::TouchPoint &touchPoint = m_touchPoints[xiDeviceEvent->detail]; + qreal x = fixed1616ToReal(xiDeviceEvent->root_x); + qreal y = fixed1616ToReal(xiDeviceEvent->root_y); + qreal nx = -1.0, ny = -1.0, d = 0.0; + QXcbScreen* screen = m_screens.at(0); + for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { + XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; + if (classinfo->type == XIValuatorClass) { + XIValuatorClassInfo *vci = reinterpret_cast(classinfo); + int n = vci->number; + double value; + if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value)) + continue; + if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) + qCDebug(lcQpaXInput, " valuator %20s value %lf from range %lf -> %lf", + atomName(vci->label).constData(), value, vci->min, vci->max ); + if (vci->label == atom(QXcbAtom::RelX)) { + nx = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::RelY)) { + ny = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsX)) { + nx = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsY)) { + ny = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsMTPositionX)) { + nx = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsMTPositionY)) { + ny = valuatorNormalized(value, vci); + } else if (vci->label == atom(QXcbAtom::AbsMTTouchMajor)) { + d = valuatorNormalized(value, vci) * screen->geometry().width(); + } else if (vci->label == atom(QXcbAtom::AbsMTPressure) || + vci->label == atom(QXcbAtom::AbsPressure)) { + touchPoint.pressure = valuatorNormalized(value, vci); + } + } + } + // If any value was not updated, use the last-known value. + if (nx == -1.0) { + x = touchPoint.area.center().x(); + nx = x / screen->geometry().width(); + } + if (ny == -1.0) { + y = touchPoint.area.center().y(); + ny = y / screen->geometry().height(); + } + if (xiDeviceEvent->evtype != XI_TouchEnd) { + if (d == 0.0) + d = touchPoint.area.width(); + } + + switch (xiDeviceEvent->evtype) { + case XI_TouchBegin: + if (firstTouch) { + dev->firstPressedPosition = QPointF(x, y); + dev->firstPressedNormalPosition = QPointF(nx, ny); + } + dev->pointPressedPosition.insert(touchPoint.id, QPointF(x, y)); + + // Touches must be accepted when we are grabbing touch events. Otherwise the entire sequence + // will get replayed when the grab ends. + if (m_xiGrab) { + // XIAllowTouchEvents deadlocks with libXi < 1.7.4 (this has nothing to do with the XI2 versions like 2.2) + // http://lists.x.org/archives/xorg-devel/2014-July/043059.html +#ifndef LIBXI_MAJOR + static bool allowTouchWarningShown = false; + if (!allowTouchWarningShown) { + allowTouchWarningShown = true; + qWarning("Skipping XIAllowTouchEvents() because it was not possible to detect libXi version at build time." + " Minimum libXi version required is 1.7.4." + " Expect issues with touch behavior."); + } +#elif LIBXI_MAJOR == 1 && (LIBXI_MINOR < 7 || (LIBXI_MINOR == 7 && LIBXI_PATCH < 4)) + static bool allowTouchWarningShown = false; + if (!allowTouchWarningShown) { + allowTouchWarningShown = true; + qWarning("Skipping XIAllowTouchEvents() due to not having libXi >= 1.7.4." + " libXi version at build time was %d.%d.%d." + " Expect issues with touch behavior.", LIBXI_MAJOR, LIBXI_MINOR, LIBXI_PATCH); + } +#else + XIAllowTouchEvents(static_cast(m_xlib_display), xiDeviceEvent->deviceid, + xiDeviceEvent->detail, xiDeviceEvent->event, XIAcceptTouch); +#endif + } + break; + case XI_TouchUpdate: + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { + qreal dx = (nx - dev->firstPressedNormalPosition.x()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + qreal dy = (ny - dev->firstPressedNormalPosition.y()) * + dev->size.height() * screen->geometry().height() / screen->physicalSize().height(); + x = dev->firstPressedPosition.x() + dx; + y = dev->firstPressedPosition.y() + dy; + touchPoint.state = Qt::TouchPointMoved; + } else if (touchPoint.area.center() != QPoint(x, y)) { + touchPoint.state = Qt::TouchPointMoved; + dev->pointPressedPosition[touchPoint.id] = QPointF(x, y); + } + break; + case XI_TouchEnd: + touchPoint.state = Qt::TouchPointReleased; + if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { + qreal dx = (nx - dev->firstPressedNormalPosition.x()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + qreal dy = (ny - dev->firstPressedNormalPosition.y()) * + dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); + x = dev->firstPressedPosition.x() + dx; + y = dev->firstPressedPosition.y() + dy; + } + dev->pointPressedPosition.remove(touchPoint.id); + } + touchPoint.area = QRectF(x - d/2, y - d/2, d, d); + touchPoint.normalPosition = QPointF(nx, ny); + + if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) + qCDebug(lcQpaXInput) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << + " area " << touchPoint.area << " pressure " << touchPoint.pressure; + QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiDeviceEvent->time, dev->qtTouchDevice, m_touchPoints.values()); + if (touchPoint.state == Qt::TouchPointReleased) + // If a touchpoint was released, we can forget it, because the ID won't be reused. + m_touchPoints.remove(touchPoint.id); + else + // Make sure that we don't send TouchPointPressed/Moved in more than one QTouchEvent + // with this touch point if the next XI2 event is about a different touch point. + touchPoint.state = Qt::TouchPointStationary; +} + +bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) +{ + if (grab && !canGrab()) + return false; + + int num_devices = 0; + Display *xDisplay = static_cast(xlib_display()); + XIDeviceInfo *info = XIQueryDevice(xDisplay, XIAllMasterDevices, &num_devices); + if (!info) + return false; + + XIEventMask evmask; + unsigned char mask[XIMaskLen(XI_LASTEVENT)]; + evmask.mask = mask; + evmask.mask_len = sizeof(mask); + memset(mask, 0, sizeof(mask)); + evmask.deviceid = XIAllMasterDevices; + + XISetMask(mask, XI_ButtonPress); + XISetMask(mask, XI_ButtonRelease); + XISetMask(mask, XI_Motion); + XISetMask(mask, XI_TouchBegin); + XISetMask(mask, XI_TouchUpdate); + XISetMask(mask, XI_TouchEnd); + + bool grabbed = true; + for (int i = 0; i < num_devices; i++) { + int id = info[i].deviceid, n = 0; + XIDeviceInfo *deviceInfo = XIQueryDevice(xDisplay, id, &n); + if (deviceInfo) { + const bool grabbable = deviceInfo->use != XIMasterKeyboard; + XIFreeDeviceInfo(deviceInfo); + if (!grabbable) + continue; + } + if (!grab) { + Status result = XIUngrabDevice(xDisplay, id, CurrentTime); + if (result != Success) { + grabbed = false; + qCDebug(lcQpaXInput, "XInput 2.2: failed to ungrab events for device %d (result %d)", id, result); + } + } else { + Status result = XIGrabDevice(xDisplay, id, w, CurrentTime, None, XIGrabModeAsync, + XIGrabModeAsync, False, &evmask); + if (result != Success) { + grabbed = false; + qCDebug(lcQpaXInput, "XInput 2.2: failed to grab events for device %d on window %x (result %d)", id, w, result); + } + } + } + + XIFreeDeviceInfo(info); + + m_xiGrab = grabbed; + + return grabbed; +} +#endif // XCB_USE_XINPUT22 + void QXcbConnection::xi2HandleHierachyEvent(void *event) { xXIHierarchyEvent *xiEvent = reinterpret_cast(event); @@ -792,7 +914,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin #endif // XCB_USE_XINPUT21 } -static Qt::MouseButton xiToQtMouseButton(uint32_t b) { +Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b) +{ switch (b) { case 1: return Qt::LeftButton; case 2: return Qt::MiddleButton; @@ -839,20 +962,29 @@ static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) { } #ifndef QT_NO_TABLETEVENT -bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) +bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, QXcbWindowEventListener *eventListener) { bool handled = true; Display *xDisplay = static_cast(m_xlib_display); xXIGenericDeviceEvent *xiEvent = static_cast(event); + xXIDeviceEvent *xiDeviceEvent = reinterpret_cast(xiEvent); + +#ifdef XCB_USE_XINPUT22 + // Synthesize mouse events since otherwise there are no mouse events from + // the pen on the XI 2.2+ path. + if (xi2MouseEvents() && eventListener) + eventListener->handleXIMouseEvent(reinterpret_cast(event)); +#endif + switch (xiEvent->evtype) { case XI_ButtonPress: { - Qt::MouseButton b = xiToQtMouseButton(reinterpret_cast(event)->detail); + Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail); tabletData->buttons |= b; xi2ReportTabletEvent(*tabletData, xiEvent); break; } case XI_ButtonRelease: { - Qt::MouseButton b = xiToQtMouseButton(reinterpret_cast(event)->detail); + Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail); tabletData->buttons ^= b; xi2ReportTabletEvent(*tabletData, xiEvent); break; @@ -915,7 +1047,7 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) // TODO maybe have a hash of tabletData->deviceId to device data so we can // look up the tablet name here, and distinguish multiple tablets qCDebug(lcQpaXInput, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d", - ev->deviceid, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID], + tabletData->deviceId, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID], ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool); } XFree(data); @@ -979,7 +1111,7 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) qCDebug(lcQpaXInput, "XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", - ev->deviceid, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail, + tabletData.deviceId, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail, fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y), fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y), (int)tabletData.buttons, pressure, xTilt, yTilt, rotation); diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 5a7c2cef83..f3bffd2998 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -47,6 +47,12 @@ #include #include +#ifdef XCB_USE_XINPUT22 +#include +#undef KeyPress +#undef KeyRelease +#endif + #ifndef XK_ISO_Left_Tab #define XK_ISO_Left_Tab 0xFE20 #endif @@ -791,6 +797,31 @@ void QXcbKeyboard::updateXKBStateFromCore(quint16 state) } } +void QXcbKeyboard::updateXKBStateFromXI(void *modInfo, void *groupInfo) +{ +#ifdef XCB_USE_XINPUT22 + if (m_config && !connection()->hasXKB()) { + xXIModifierInfo *mods = static_cast(modInfo); + xXIGroupInfo *group = static_cast(groupInfo); + const xkb_state_component newState = xkb_state_update_mask(xkb_state, + mods->base_mods, + mods->latched_mods, + mods->locked_mods, + group->base_group, + group->latched_group, + group->locked_group); + + if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) { + //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)"); + } + } +#else + Q_UNUSED(modInfo); + Q_UNUSED(groupInfo); + Q_ASSERT(false); // this can't be +#endif +} + quint32 QXcbKeyboard::xkbModMask(quint16 state) { quint32 xkb_mask = 0; diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 2281674e2f..d2e37d624c 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -68,6 +68,7 @@ public: void updateXKBMods(); quint32 xkbModMask(quint16 state); void updateXKBStateFromCore(quint16 state); + void updateXKBStateFromXI(void *modInfo, void *groupInfo); #ifndef QT_NO_XKB // when XKEYBOARD is present on the X server int coreDeviceId() const { return core_device_id; } diff --git a/src/plugins/platforms/xcb/qxcbmain.cpp b/src/plugins/platforms/xcb/qxcbmain.cpp index 0c3e8b5cd3..4a07b66491 100644 --- a/src/plugins/platforms/xcb/qxcbmain.cpp +++ b/src/plugins/platforms/xcb/qxcbmain.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QXcbIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "xcb.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "xcb.json") public: QPlatformIntegration *create(const QString&, const QStringList&, int &, char **) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 076cc1aa80..d2da137591 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -97,6 +97,7 @@ #if defined(XCB_USE_XINPUT2) #include +#include #endif #define XCOORD_MAX 16383 @@ -2167,16 +2168,17 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) } } -void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) +void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y, + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) { - const bool isWheel = event->detail >= 4 && event->detail <= 7; + const bool isWheel = detail >= 4 && detail <= 7; if (!isWheel && window() != QGuiApplication::focusWindow()) { QWindow *w = static_cast(QObjectPrivate::get(window()))->eventReceiver(); if (!(w->flags() & Qt::WindowDoesNotAcceptFocus)) w->requestActivate(); } - updateNetWmUserTime(event->time); + updateNetWmUserTime(timestamp); if (m_embedded) { if (window() != QGuiApplication::focusWindow()) { @@ -2187,53 +2189,125 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) } } const int dpr = int(devicePixelRatio()); - QPoint local(event->event_x/dpr, event->event_y/dpr); - QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); - - Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); + QPoint local(event_x / dpr, event_y / dpr); + QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); if (isWheel) { - if (!connection()->isUsingXInput21()) { + if (!connection()->isAtLeastXI21()) { // 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) + int delta = 120 * ((detail == 4 || detail == 6) ? 1 : -1); + bool hor = (((detail == 4 || detail == 5) && (modifiers & Qt::AltModifier)) - || (event->detail == 6 || event->detail == 7)); + || (detail == 6 || detail == 7)); - QWindowSystemInterface::handleWheelEvent(window(), event->time, + QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers); } return; } - handleMouseEvent(event->time, local, global, modifiers); + handleMouseEvent(timestamp, local, global, modifiers); } -void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event) +void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y, + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) { const int dpr = int(devicePixelRatio()); - QPoint local(event->event_x/dpr, event->event_y/dpr); - QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); - Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); + QPoint local(event_x / dpr, event_y / dpr); + QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); - if (event->detail >= 4 && event->detail <= 7) { + if (detail >= 4 && detail <= 7) { // mouse wheel, handled in handleButtonPressEvent() return; } - handleMouseEvent(event->time, local, global, modifiers); + handleMouseEvent(timestamp, local, global, modifiers); +} + +void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y, + Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) +{ + if (!xcbScreen()) + return; + const int dpr = int(devicePixelRatio()); + QPoint local(event_x / dpr, event_y / dpr); + QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); + handleMouseEvent(timestamp, local, global, modifiers); +} + +// Handlers for plain xcb events. Used only when XI 2.2 or newer is not available. +void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) +{ + Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); + handleButtonPressEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->detail, + modifiers, event->time); +} + +void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event) +{ + Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); + handleButtonReleaseEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->detail, + modifiers, event->time); } void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) { - const int dpr = int(devicePixelRatio()); - QPoint local(event->event_x/dpr, event->event_y/dpr); - if (!xcbScreen()) - return; - QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); + handleMotionNotifyEvent(event->event_x, event->event_y, event->root_x, event->root_y, modifiers, event->time); +} - handleMouseEvent(event->time, local, global, modifiers); +#ifdef XCB_USE_XINPUT22 +static inline int fixed1616ToInt(FP1616 val) +{ + return int((qreal(val >> 16)) + (val & 0xFFFF) / (qreal)0xFFFF); +} +#endif + +// With XI 2.2+ press/release/motion comes here instead of the above handlers. +void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event) +{ +#ifdef XCB_USE_XINPUT22 + QXcbConnection *conn = connection(); + xXIDeviceEvent *ev = reinterpret_cast(event); + const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective_mods); + const int event_x = fixed1616ToInt(ev->event_x); + const int event_y = fixed1616ToInt(ev->event_y); + const int root_x = fixed1616ToInt(ev->root_x); + const int root_y = fixed1616ToInt(ev->root_y); + + conn->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group); + + const Qt::MouseButton button = conn->xiToQtMouseButton(ev->detail); + + if (ev->buttons_len > 0) { + unsigned char *buttonMask = (unsigned char *) &ev[1]; + for (int i = 1; i <= 15; ++i) + conn->setButton(conn->translateMouseButton(i), XIMaskIsSet(buttonMask, i)); + } + + switch (ev->evtype) { + case XI_ButtonPress: + qCDebug(lcQpaXInput, "XI2 mouse press, button %d", button); + conn->setButton(button, true); + handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time); + break; + case XI_ButtonRelease: + qCDebug(lcQpaXInput, "XI2 mouse release, button %d", button); + conn->setButton(button, false); + handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time); + break; + case XI_Motion: + qCDebug(lcQpaXInput, "XI2 mouse motion %d,%d", event_x, event_y); + handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time); + break; + default: + qWarning() << "Unrecognized XI2 mouse event" << ev->evtype; + break; + } +#else + Q_UNUSED(event); + Q_ASSERT(false); // this can't be +#endif } QXcbWindow *QXcbWindow::toWindow() { return this; } @@ -2417,6 +2491,10 @@ bool QXcbWindow::setKeyboardGrabEnabled(bool grab) bool QXcbWindow::setMouseGrabEnabled(bool grab) { +#ifdef XCB_USE_XINPUT22 + if (connection()->xi2MouseEvents()) + return connection()->xi2SetMouseGrabEnabled(m_window, grab); +#endif if (grab && !connection()->canGrab()) return false; diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 52e8ac1459..07019223c8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -132,6 +132,7 @@ public: void handleFocusInEvent(const xcb_focus_in_event_t *event) Q_DECL_OVERRIDE; void handleFocusOutEvent(const xcb_focus_out_event_t *event) Q_DECL_OVERRIDE; void handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) Q_DECL_OVERRIDE; + void handleXIMouseEvent(xcb_ge_event_t *) Q_DECL_OVERRIDE; QXcbWindow *toWindow() Q_DECL_OVERRIDE; @@ -210,6 +211,15 @@ protected: void doFocusIn(); void doFocusOut(); + void handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y, + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp); + + void handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y, + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp); + + void handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y, + Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp); + xcb_window_t m_window; QXcbScreen *m_xcbScreen; diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index fd704dd904..12987567ff 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -59,6 +59,11 @@ contains(QT_CONFIG, xcb-xlib) { DEFINES += XCB_USE_XINPUT2 SOURCES += qxcbconnection_xi2.cpp LIBS += -lXi + !isEmpty(QMAKE_LIBXI_VERSION_MAJOR) { + DEFINES += LIBXI_MAJOR=$$QMAKE_LIBXI_VERSION_MAJOR \ + LIBXI_MINOR=$$QMAKE_LIBXI_VERSION_MINOR \ + LIBXI_PATCH=$$QMAKE_LIBXI_VERSION_PATCH + } } } diff --git a/src/plugins/platformthemes/gtk2/main.cpp b/src/plugins/platformthemes/gtk2/main.cpp index 2431443dfa..34ac3ffc07 100644 --- a/src/plugins/platformthemes/gtk2/main.cpp +++ b/src/plugins/platformthemes/gtk2/main.cpp @@ -39,7 +39,7 @@ QT_BEGIN_NAMESPACE class QGtk2ThemePlugin : public QPlatformThemePlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformThemeFactoryInterface.5.1" FILE "gtk2.json") + Q_PLUGIN_METADATA(IID QPlatformThemeFactoryInterface_iid FILE "gtk2.json") public: QPlatformTheme *create(const QString &key, const QStringList ¶ms) Q_DECL_OVERRIDE; diff --git a/src/plugins/printsupport/cocoa/main.cpp b/src/plugins/printsupport/cocoa/main.cpp index d0925bbc34..2037724719 100644 --- a/src/plugins/printsupport/cocoa/main.cpp +++ b/src/plugins/printsupport/cocoa/main.cpp @@ -43,7 +43,7 @@ QT_BEGIN_NAMESPACE class QCocoaPrinterSupportPlugin : public QPlatformPrinterSupportPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.QPlatformPrinterSupportFactoryInterface" FILE "cocoa.json") + Q_PLUGIN_METADATA(IID QPlatformPrinterSupportFactoryInterface_iid FILE "cocoa.json") public: QPlatformPrinterSupport *create(const QString &); diff --git a/src/plugins/printsupport/cups/main.cpp b/src/plugins/printsupport/cups/main.cpp index 9651a074cc..82485114ab 100644 --- a/src/plugins/printsupport/cups/main.cpp +++ b/src/plugins/printsupport/cups/main.cpp @@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE class QCupsPrinterSupportPlugin : public QPlatformPrinterSupportPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.QPlatformPrinterSupportFactoryInterface" FILE "cups.json") + Q_PLUGIN_METADATA(IID QPlatformPrinterSupportFactoryInterface_iid FILE "cups.json") public: QStringList keys() const; diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp index c2bd2872a9..808424b1ed 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.cpp +++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp @@ -89,16 +89,6 @@ QPpdPrintDevice::QPpdPrintDevice(const QString &id) } } -QPpdPrintDevice::QPpdPrintDevice(const QPpdPrintDevice &other) - : QPlatformPrintDevice(other), - m_cupsDest(0), - m_ppd(0) -{ - m_cupsName = other.m_cupsName; - m_cupsInstance = other.m_cupsInstance; - loadPrinter(); -} - QPpdPrintDevice::~QPpdPrintDevice() { if (m_ppd) @@ -109,20 +99,6 @@ QPpdPrintDevice::~QPpdPrintDevice() m_ppd = 0; } -QPpdPrintDevice &QPpdPrintDevice::operator=(const QPpdPrintDevice &other) -{ - m_cupsName = other.m_cupsName; - m_cupsInstance = other.m_cupsInstance; - if (other.m_cupsDest && other.m_ppd) - loadPrinter(); - return *this; -} - -bool QPpdPrintDevice::operator==(const QPpdPrintDevice &other) const -{ - return (m_id == other.m_id); -} - bool QPpdPrintDevice::isValid() const { return m_cupsDest && m_ppd; diff --git a/src/plugins/printsupport/cups/qppdprintdevice.h b/src/plugins/printsupport/cups/qppdprintdevice.h index 2437234d28..64eb872bd1 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.h +++ b/src/plugins/printsupport/cups/qppdprintdevice.h @@ -63,15 +63,8 @@ class QPpdPrintDevice : public QPlatformPrintDevice public: QPpdPrintDevice(); explicit QPpdPrintDevice(const QString &id); - QPpdPrintDevice(const QPpdPrintDevice &other); virtual ~QPpdPrintDevice(); - QPpdPrintDevice &operator=(const QPpdPrintDevice &other); - - QPpdPrintDevice *clone(); - - bool operator==(const QPpdPrintDevice &other) const; - bool isValid() const Q_DECL_OVERRIDE; bool isDefault() const Q_DECL_OVERRIDE; diff --git a/src/plugins/printsupport/windows/main.cpp b/src/plugins/printsupport/windows/main.cpp index f1ee620b8b..28e99f1916 100644 --- a/src/plugins/printsupport/windows/main.cpp +++ b/src/plugins/printsupport/windows/main.cpp @@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE class QWindowsPrinterSupportPlugin : public QPlatformPrinterSupportPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.QPlatformPrinterSupportFactoryInterface" FILE "windows.json") + Q_PLUGIN_METADATA(IID QPlatformPrinterSupportFactoryInterface_iid FILE "windows.json") public: QPlatformPrinterSupport *create(const QString &); diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp index af8e07edd2..505f3138ca 100644 --- a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp +++ b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp @@ -113,28 +113,11 @@ QWindowsPrintDevice::QWindowsPrintDevice(const QString &id) } } -QWindowsPrintDevice::QWindowsPrintDevice(const QWindowsPrintDevice &other) - : QPlatformPrintDevice(other) -{ - OpenPrinter((LPWSTR)other.m_id.utf16(), &m_hPrinter, NULL); -} - QWindowsPrintDevice::~QWindowsPrintDevice() { ClosePrinter(m_hPrinter); } -QWindowsPrintDevice &QWindowsPrintDevice::operator=(const QWindowsPrintDevice &other) -{ - OpenPrinter((LPWSTR)other.m_id.utf16(), &m_hPrinter, NULL); - return *this; -} - -bool QWindowsPrintDevice::operator==(const QWindowsPrintDevice &other) const -{ - return (m_id == other.m_id); -} - bool QWindowsPrintDevice::isValid() const { return m_hPrinter; diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.h b/src/plugins/printsupport/windows/qwindowsprintdevice.h index 2e0f6e4658..8ab487a59c 100644 --- a/src/plugins/printsupport/windows/qwindowsprintdevice.h +++ b/src/plugins/printsupport/windows/qwindowsprintdevice.h @@ -58,15 +58,8 @@ class QWindowsPrintDevice : public QPlatformPrintDevice public: QWindowsPrintDevice(); explicit QWindowsPrintDevice(const QString &id); - QWindowsPrintDevice(const QWindowsPrintDevice &other); virtual ~QWindowsPrintDevice(); - QWindowsPrintDevice &operator=(const QWindowsPrintDevice &other); - - QWindowsPrintDevice *clone(); - - bool operator==(const QWindowsPrintDevice &other) const; - bool isValid() const Q_DECL_OVERRIDE; bool isDefault() const Q_DECL_OVERRIDE; diff --git a/src/printsupport/kernel/qplatformprintdevice.cpp b/src/printsupport/kernel/qplatformprintdevice.cpp index bd6d81774c..6385f58aa1 100644 --- a/src/printsupport/kernel/qplatformprintdevice.cpp +++ b/src/printsupport/kernel/qplatformprintdevice.cpp @@ -75,11 +75,6 @@ QPlatformPrintDevice::~QPlatformPrintDevice() { } -bool QPlatformPrintDevice::operator==(const QPlatformPrintDevice &other) const -{ - return m_id == other.m_id; -} - QString QPlatformPrintDevice::id() const { return m_id; diff --git a/src/printsupport/kernel/qplatformprintdevice.h b/src/printsupport/kernel/qplatformprintdevice.h index 1e21e608ad..8bb87a70f9 100644 --- a/src/printsupport/kernel/qplatformprintdevice.h +++ b/src/printsupport/kernel/qplatformprintdevice.h @@ -55,17 +55,14 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_PRINTER -class Q_PRINTSUPPORT_EXPORT QPlatformPrintDevice : public QSharedData +class Q_PRINTSUPPORT_EXPORT QPlatformPrintDevice { + Q_DISABLE_COPY(QPlatformPrintDevice) public: QPlatformPrintDevice(); explicit QPlatformPrintDevice(const QString &id); virtual ~QPlatformPrintDevice(); - QPlatformPrintDevice *clone(); - - bool operator==(const QPlatformPrintDevice &other) const; - virtual QString id() const; virtual QString name() const; virtual QString location() const; diff --git a/src/printsupport/kernel/qplatformprintplugin.h b/src/printsupport/kernel/qplatformprintplugin.h index 279de9b952..ad39bf5a0c 100644 --- a/src/printsupport/kernel/qplatformprintplugin.h +++ b/src/printsupport/kernel/qplatformprintplugin.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE class QPlatformPrinterSupport; -#define QPlatformPrinterSupportFactoryInterface_iid "org.qt-project.QPlatformPrinterSupportFactoryInterface" +#define QPlatformPrinterSupportFactoryInterface_iid "org.qt-project.QPlatformPrinterSupportFactoryInterface.5.1" class Q_PRINTSUPPORT_EXPORT QPlatformPrinterSupportPlugin : public QObject { diff --git a/src/printsupport/kernel/qprintdevice.cpp b/src/printsupport/kernel/qprintdevice.cpp index 7c18b53e09..a640c14483 100644 --- a/src/printsupport/kernel/qprintdevice.cpp +++ b/src/printsupport/kernel/qprintdevice.cpp @@ -73,7 +73,7 @@ QPrintDevice &QPrintDevice::operator=(const QPrintDevice &other) bool QPrintDevice::operator==(const QPrintDevice &other) const { if (d && other.d) - return *d == *other.d; + return d->id() == other.d->id(); return d == other.d; } diff --git a/src/printsupport/kernel/qprintdevice_p.h b/src/printsupport/kernel/qprintdevice_p.h index ad55cded0e..ddf5595734 100644 --- a/src/printsupport/kernel/qprintdevice_p.h +++ b/src/printsupport/kernel/qprintdevice_p.h @@ -136,7 +136,7 @@ private: friend class QPlatformPrinterSupport; friend class QPlatformPrintDevice; QPrintDevice(QPlatformPrintDevice *dd); - QSharedDataPointer d; + QSharedPointer d; }; Q_DECLARE_SHARED(QPrintDevice) diff --git a/src/printsupport/kernel/qprinter.cpp b/src/printsupport/kernel/qprinter.cpp index 246dae0ddf..a106a58502 100644 --- a/src/printsupport/kernel/qprinter.cpp +++ b/src/printsupport/kernel/qprinter.cpp @@ -1764,7 +1764,7 @@ QRectF QPrinter::paperRect(Unit unit) const } /*! - \obsolete Use pageLayout().paintRect() instead. + \obsolete Use pageLayout().paintRectPixels(resolution()) instead. Returns the page's rectangle; this is usually smaller than the paperRect() since the page normally has margins between its @@ -1781,7 +1781,7 @@ QRect QPrinter::pageRect() const } /*! - \obsolete Use pageLayout().fullPageRect() instead. + \obsolete Use pageLayout().fullRectPixels(resolution()) instead. Returns the paper's rectangle; this is usually larger than the pageRect(). diff --git a/src/printsupport/widgets/qprintpreviewwidget.cpp b/src/printsupport/widgets/qprintpreviewwidget.cpp index 6033381b58..686dab07bf 100644 --- a/src/printsupport/widgets/qprintpreviewwidget.cpp +++ b/src/printsupport/widgets/qprintpreviewwidget.cpp @@ -335,8 +335,8 @@ void QPrintPreviewWidgetPrivate::populateScene() pages.clear(); int numPages = pictures.count(); - QSize paperSize = printer->paperRect().size(); - QRect pageRect = printer->pageRect(); + QSize paperSize = printer->pageLayout().fullRectPixels(printer->resolution()).size(); + QRect pageRect = printer->pageLayout().paintRectPixels(printer->resolution()); for (int i = 0; i < numPages; i++) { PageItem* item = new PageItem(i+1, pictures.at(i), paperSize, pageRect); diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp index 6262c25e0d..c35fca7217 100644 --- a/src/sql/kernel/qsqlresult.cpp +++ b/src/sql/kernel/qsqlresult.cpp @@ -837,6 +837,9 @@ QString QSqlResult::executedQuery() const return d->executedQuery; } +/*! + Resets the number of bind parameters. +*/ void QSqlResult::resetBindCount() { Q_D(QSqlResult); diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index b687ae568d..b0d3e6df9d 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -1302,6 +1302,14 @@ Qt::ItemFlags QSqlTableModel::flags(const QModelIndex &index) const return QSqlQueryModel::flags(index) | Qt::ItemIsEditable; } +/*! + This is an overloaded function. + + It returns an empty record, having only the field names. This function can be used to + retrieve the field names of a record. + + \sa QSqlRecord::isEmpty() +*/ QSqlRecord QSqlTableModel::record() const { return QSqlQueryModel::record(); diff --git a/src/testlib/doc/qttestlib.qdocconf b/src/testlib/doc/qttestlib.qdocconf index 35b4fbcb7b..0fafc733b1 100644 --- a/src/testlib/doc/qttestlib.qdocconf +++ b/src/testlib/doc/qttestlib.qdocconf @@ -40,5 +40,8 @@ excludedirs += ../../../examples/widgets/doc imagedirs += images +# Add a thumbnail for examples that do not have images +manifestmeta.thumbnail.names = "QtTestLib/Chapter *" + navigation.landingpage = "Qt Test" navigation.cppclassespage = "Qt Test C++ Classes" diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index 81cc07c410..994179958b 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -274,14 +274,33 @@ inline bool qCompare(quint32 const &t1, quint64 const &t2, const char *actual, } QT_END_NAMESPACE +#ifdef QT_TESTCASE_BUILDDIR +# define QTEST_SET_MAIN_SOURCE_PATH QTest::setMainSourcePath(__FILE__, QT_TESTCASE_BUILDDIR); +#else +# define QTEST_SET_MAIN_SOURCE_PATH QTest::setMainSourcePath(__FILE__); +#endif + #define QTEST_APPLESS_MAIN(TestObject) \ int main(int argc, char *argv[]) \ { \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } #include +#include + +#ifndef QT_NO_OPENGL +# define QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ + extern Q_TESTLIB_EXPORT std::set *(*qgpu_features_ptr)(const QString &); \ + extern Q_GUI_EXPORT std::set *qgpu_features(const QString &); +# define QTEST_ADD_GPU_BLACKLIST_SUPPORT \ + qgpu_features_ptr = qgpu_features; +#else +# define QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS +# define QTEST_ADD_GPU_BLACKLIST_SUPPORT +#endif #if defined(QT_WIDGETS_LIB) @@ -294,12 +313,17 @@ int main(int argc, char *argv[]) \ #endif #define QTEST_MAIN(TestObject) \ +QT_BEGIN_NAMESPACE \ +QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ +QT_END_NAMESPACE \ int main(int argc, char *argv[]) \ { \ QApplication app(argc, argv); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ QTEST_DISABLE_KEYPAD_NAVIGATION \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } @@ -308,11 +332,16 @@ int main(int argc, char *argv[]) \ #include #define QTEST_MAIN(TestObject) \ +QT_BEGIN_NAMESPACE \ +QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ +QT_END_NAMESPACE \ int main(int argc, char *argv[]) \ { \ QGuiApplication app(argc, argv); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ + QTEST_ADD_GPU_BLACKLIST_SUPPORT \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } @@ -324,6 +353,7 @@ int main(int argc, char *argv[]) \ QCoreApplication app(argc, argv); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } @@ -335,6 +365,7 @@ int main(int argc, char *argv[]) \ QCoreApplication app(argc, argv); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ TestObject tc; \ + QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ } diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp index bfeca08617..f9ce908a00 100644 --- a/src/testlib/qtestblacklist.cpp +++ b/src/testlib/qtestblacklist.cpp @@ -34,6 +34,7 @@ #include "qtestresult_p.h" #include +#include #include #include #include @@ -161,6 +162,9 @@ static bool checkCondition(const QByteArray &condition) static bool ignoreAll = false; static std::set *ignoredTests = 0; +static std::set *gpuFeatures = 0; + +Q_TESTLIB_EXPORT std::set *(*qgpu_features_ptr)(const QString &) = 0; namespace QTestPrivate { @@ -196,7 +200,18 @@ void parseBlackList() } } -void checkBlackList(const char *slot, const char *data) +void parseGpuBlackList() +{ + if (!qgpu_features_ptr) + return; + QString filename = QTest::qFindTestData(QStringLiteral("GPU_BLACKLIST")); + if (filename.isEmpty()) + return; + if (!gpuFeatures) + gpuFeatures = qgpu_features_ptr(filename); +} + +void checkBlackLists(const char *slot, const char *data) { bool ignore = ignoreAll; @@ -211,6 +226,16 @@ void checkBlackList(const char *slot, const char *data) } QTestResult::setBlacklistCurrentTest(ignore); + + // Tests blacklisted in GPU_BLACKLIST are to be skipped. Just ignoring the result is + // not sufficient since these are expected to crash or behave in undefined ways. + if (!ignore && gpuFeatures) { + const QByteArray disableKey = QByteArrayLiteral("disable_") + QByteArray(slot); + if (gpuFeatures->find(disableKey) != gpuFeatures->end()) { + const QByteArray msg = QByteArrayLiteral("Skipped due to GPU blacklist: ") + disableKey; + QTest::qSkip(msg.constData(), __FILE__, __LINE__); + } + } } } diff --git a/src/testlib/qtestblacklist_p.h b/src/testlib/qtestblacklist_p.h index 158d99593e..0107e5d282 100644 --- a/src/testlib/qtestblacklist_p.h +++ b/src/testlib/qtestblacklist_p.h @@ -51,7 +51,8 @@ QT_BEGIN_NAMESPACE namespace QTestPrivate { void parseBlackList(); - void checkBlackList(const char *slot, const char *data); + void parseGpuBlackList(); + void checkBlackLists(const char *slot, const char *data); } QT_END_NAMESPACE diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index e1e6805a0f..858475f396 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1374,6 +1374,7 @@ static bool installCoverageTool(const char * appname, const char * testname) namespace QTest { static QObject *currentTestObject = 0; + static QString mainSourcePath; class TestFunction { public: @@ -2167,7 +2168,7 @@ static bool qInvokeTestMethod(const char *slotName, const char *data, WatchDog * if (!data || !qstrcmp(data, table.testData(curDataIndex)->dataTag())) { foundFunction = true; - QTestPrivate::checkBlackList(slot, dataCount ? table.testData(curDataIndex)->dataTag() : 0); + QTestPrivate::checkBlackLists(slot, dataCount ? table.testData(curDataIndex)->dataTag() : 0); QTestDataSetter s(curDataIndex >= dataCount ? static_cast(0) : table.testData(curDataIndex)); @@ -2682,6 +2683,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) #endif QTestPrivate::parseBlackList(); + QTestPrivate::parseGpuBlackList(); QTestResult::reset(); @@ -3032,6 +3034,13 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co found = candidate; } + // 6. Try main source directory + if (found.isEmpty()) { + QString candidate = QTest::mainSourcePath % QLatin1Char('/') % base; + if (QFileInfo(candidate).exists()) + found = candidate; + } + if (found.isEmpty()) { QTest::qWarn(qPrintable( QString::fromLatin1("testdata %1 could not be located!").arg(base)), @@ -3218,6 +3227,19 @@ QObject *QTest::testObject() return currentTestObject; } +/*! \internal + */ +void QTest::setMainSourcePath(const char *file, const char *builddir) +{ + QString mainSourceFile = QFile::decodeName(file); + QFileInfo fi; + if (builddir) + fi.setFile(QDir(QFile::decodeName(builddir)), mainSourceFile); + else + fi.setFile(mainSourceFile); + QTest::mainSourcePath = fi.absolutePath(); +} + /*! \internal This function is called by various specializations of QTest::qCompare to decide whether to report a failure and to produce verbose test output. diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index 45290de6de..2c6a94faa1 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -236,6 +236,8 @@ namespace QTest Q_TESTLIB_EXPORT int qExec(QObject *testObject, int argc = 0, char **argv = 0); Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments); + Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = 0); + Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description, const char *file, int line); Q_TESTLIB_EXPORT void qFail(const char *statementStr, const char *file, int line); diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h index fa6bb29d3a..83ea3dd0a5 100644 --- a/src/testlib/qtestmouse.h +++ b/src/testlib/qtestmouse.h @@ -202,7 +202,7 @@ namespace QTest } QSpontaneKeyEvent::setSpontaneous(&me); if (!qApp->notify(widget, &me)) { - static const char *mouseActionNames[] = + static const char *const mouseActionNames[] = { "MousePress", "MouseRelease", "MouseClick", "MouseDClick", "MouseMove" }; QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving widget"); QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast(action)])).toLatin1().data()); diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 8b6a0519c5..5be58d3c4b 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -448,7 +448,8 @@ void Generator::generateCode() // Generate internal qt_static_metacall() function // const bool hasStaticMetaCall = !isQt && - (cdef->hasQObject || !cdef->methodList.isEmpty() || !cdef->propertyList.isEmpty()); + (cdef->hasQObject || !cdef->methodList.isEmpty() + || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty()); if (hasStaticMetaCall) generateStaticMetacall(); @@ -1125,7 +1126,8 @@ void Generator::generateStaticMetacall() fprintf(out, "%s", QByteArray("QPrivateSignal()").constData()); } fprintf(out, ");\n"); - fprintf(out, " if (_a[0]) *reinterpret_cast(_a[0]) = _r; } break;\n"); + fprintf(out, " if (_a[0]) *reinterpret_cast<%s**>(_a[0]) = _r; } break;\n", + cdef->hasQGadget ? "void" : "QObject"); } fprintf(out, " default: break;\n"); fprintf(out, " }\n"); diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp index 51873033c7..f253c49995 100644 --- a/src/tools/moc/preprocessor.cpp +++ b/src/tools/moc/preprocessor.cpp @@ -661,8 +661,10 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym expansion += s; } } else if (mode == Hash) { - if (index < 0) + if (index < 0 || index >= arguments.size()) { that->error("'#' is not followed by a macro parameter"); + continue; + } const Symbols &arg = arguments.at(index); QByteArray stringified; @@ -681,7 +683,7 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym expansion.pop_back(); Symbol next = s; - if (index >= 0) { + if (index >= 0 && index < arguments.size()) { const Symbols &arg = arguments.at(index); if (arg.size() == 0) { mode = Normal; @@ -703,7 +705,7 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym expansion += next; } - if (index >= 0) { + if (index >= 0 && index < arguments.size()) { const Symbols &arg = arguments.at(index); for (int i = 1; i < arg.size(); ++i) expansion += arg.at(i); diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index 18e538ef7b..e80187ec93 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -2191,7 +2191,7 @@ void HtmlGenerator::generateRequisites(Aggregate *inner, CodeMarker *marker) out() << "
\n"; QStringList::ConstIterator i; - for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) { + for (i = requisiteorder.constBegin(); i != requisiteorder.constEnd(); ++i) { if (requisites.contains(*i)) { out() << "" @@ -2311,7 +2311,7 @@ void HtmlGenerator::generateQmlRequisites(QmlTypeNode *qcn, CodeMarker *marker) out() << "
\n"; QStringList::ConstIterator i; - for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) { + for (i = requisiteorder.constBegin(); i != requisiteorder.constEnd(); ++i) { if (requisites.contains(*i)) { out() << "" @@ -4536,33 +4536,49 @@ void HtmlGenerator::generateManifestFile(const QString &manifest, const QString writer.writeCDATA(QString("No description available")); writer.writeEndElement(); // description - // Add words from module name as tags (QtQuickControls -> qt,quick,controls) - QRegExp re("([A-Z]+[a-z0-9]*)"); + // Add words from module name as tags + // QtQuickControls -> qt,quick,controls + // QtOpenGL -> qt,opengl + QRegExp re("([A-Z]+[a-z0-9]*(3D|GL)?)"); int pos = 0; while ((pos = re.indexIn(project, pos)) != -1) { tags << re.cap(1).toLower(); pos += re.matchedLength(); } tags += QSet::fromList(en->title().toLower().split(QLatin1Char(' '))); + + // Clean up tags, exclude invalid and common words + QSet::iterator tag_it = tags.begin(); + QSet modified; + while (tag_it != tags.end()) { + QString s = *tag_it; + if (s.at(0) == '(') + s.remove(0, 1).chop(1); + if (s.endsWith(QLatin1Char(':'))) + s.chop(1); + + if (s.length() < 2 + || s.at(0).isDigit() + || s.at(0) == '-' + || s == QStringLiteral("qt") + || s == QStringLiteral("the") + || s == QStringLiteral("and") + || s.startsWith(QStringLiteral("example")) + || s.startsWith(QStringLiteral("chapter"))) + tag_it = tags.erase(tag_it); + else if (s != *tag_it) { + modified << s; + tag_it = tags.erase(tag_it); + } + else + ++tag_it; + } + tags += modified; + if (!tags.isEmpty()) { writer.writeStartElement("tags"); bool wrote_one = false; - // Exclude invalid and common words foreach (QString tag, tags) { - if (tag.length() < 2) - continue; - if (tag.at(0).isDigit()) - continue; - if (tag.at(0) == '-') - continue; - if (tag == QLatin1String("qt")) - continue; - if (tag.startsWith("example")) - continue; - if (tag.startsWith("chapter")) - continue; - if (tag.endsWith(QLatin1Char(':'))) - tag.chop(1); if (wrote_one) writer.writeCharacters(","); writer.writeCharacters(tag); diff --git a/src/tools/qdoc/location.cpp b/src/tools/qdoc/location.cpp index 12dc9e1b4c..5eba2a69ef 100644 --- a/src/tools/qdoc/location.cpp +++ b/src/tools/qdoc/location.cpp @@ -256,7 +256,7 @@ QString Location::canonicalRelativePath(const QString &path) */ void Location::warning(const QString& message, const QString& details) const { - if (!Generator::preparing()) + if (!Generator::preparing() || Generator::singleExec()) emitMessage(Warning, message, details); } @@ -267,7 +267,7 @@ void Location::warning(const QString& message, const QString& details) const */ void Location::error(const QString& message, const QString& details) const { - if (!Generator::preparing()) + if (!Generator::preparing() || Generator::singleExec()) emitMessage(Error, message, details); } diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp index ec721aee64..dbe397357c 100644 --- a/src/tools/qdoc/node.cpp +++ b/src/tools/qdoc/node.cpp @@ -2760,8 +2760,8 @@ bool CollectionNode::hasNamespaces() const bool CollectionNode::hasClasses() const { if (!members_.isEmpty()) { - NodeList::const_iterator i = members_.begin(); - while (i != members_.end()) { + NodeList::const_iterator i = members_.cbegin(); + while (i != members_.cend()) { if ((*i)->isClass()) return true; ++i; @@ -2777,8 +2777,8 @@ bool CollectionNode::hasClasses() const void CollectionNode::getMemberNamespaces(NodeMap& out) { out.clear(); - NodeList::const_iterator i = members_.begin(); - while (i != members_.end()) { + NodeList::const_iterator i = members_.cbegin(); + while (i != members_.cend()) { if ((*i)->isNamespace()) out.insert((*i)->name(),(*i)); ++i; @@ -2792,8 +2792,8 @@ void CollectionNode::getMemberNamespaces(NodeMap& out) void CollectionNode::getMemberClasses(NodeMap& out) { out.clear(); - NodeList::const_iterator i = members_.begin(); - while (i != members_.end()) { + NodeList::const_iterator i = members_.cbegin(); + while (i != members_.cend()) { if ((*i)->isClass()) out.insert((*i)->name(),(*i)); ++i; diff --git a/src/tools/qdoc/puredocparser.cpp b/src/tools/qdoc/puredocparser.cpp index 6b644cac31..bfd3925353 100644 --- a/src/tools/qdoc/puredocparser.cpp +++ b/src/tools/qdoc/puredocparser.cpp @@ -188,8 +188,8 @@ bool PureDocParser::processQdocComments() topics.insert(i+1,"and"); doc.location().warning(tr("Multiple topic commands found in comment: %1").arg(topics)); } - ArgList::ConstIterator a = args.begin(); - while (a != args.end()) { + ArgList::ConstIterator a = args.cbegin(); + while (a != args.cend()) { Doc nodeDoc = doc; Node* node = processTopicCommand(nodeDoc,topic,*a); if (node != 0) { diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp index fca34b0a6a..f10072a943 100644 --- a/src/tools/qdoc/qdocdatabase.cpp +++ b/src/tools/qdoc/qdocdatabase.cpp @@ -1549,8 +1549,8 @@ void QDocDatabase::mergeCollections(Node::Genus genus, CNMap& cnm, const Node* r foreach (Tree* t, searchOrder()) { CNMap* m = t->getCollectionMap(genus); if (m && !m->isEmpty()) { - CNMap::const_iterator i = m->begin(); - while (i != m->end()) { + CNMap::const_iterator i = m->cbegin(); + while (i != m->cend()) { if (!i.value()->isInternal()) cnmm.insert(i.key(), i.value()); ++i; diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp index 0da963fe0b..629514e7d1 100644 --- a/src/tools/qdoc/tree.cpp +++ b/src/tools/qdoc/tree.cpp @@ -1222,8 +1222,8 @@ CollectionNode* Tree::getCollection(const QString& name, Node::Genus genus) { CNMap* m = getCollectionMap(genus); if (m) { - CNMap::const_iterator i = m->find(name); - if (i != m->end()) + CNMap::const_iterator i = m->constFind(name); + if (i != m->cend()) return i.value(); } return 0; @@ -1249,8 +1249,8 @@ CollectionNode* Tree::findCollection(const QString& name, Node::Genus genus) CNMap* m = getCollectionMap(genus); if (!m) // error return 0; - CNMap::const_iterator i = m->find(name); - if (i != m->end()) + CNMap::const_iterator i = m->constFind(name); + if (i != m->cend()) return i.value(); Node::NodeType t = Node::NoType; switch (genus) { diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp index 65def6d4b8..6676a3ccba 100644 --- a/src/widgets/dialogs/qdialog.cpp +++ b/src/widgets/dialogs/qdialog.cpp @@ -534,7 +534,10 @@ int QDialog::exec() QPointer guard = this; if (d->nativeDialogInUse) { - d->platformHelper()->exec(); + if (windowModality() == Qt::WindowModal) + d->platformHelper()->execModalForWindow(d->parentWindow()); + else + d->platformHelper()->exec(); } else { QEventLoop eventLoop; d->eventLoop = &eventLoop; diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 1be2f93478..41522bfa19 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -893,6 +893,12 @@ void QFileDialogPrivate::_q_goToUrl(const QUrl &url) /*! Sets the file dialog's current \a directory. + + \note On iOS, if you set \a directory to \l{QStandardPaths::standardLocations()} + {QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()}, + a native image picker dialog will be used for accessing the user's photo album. + The filename returned can be loaded using QFile and related APIs. + This feature was added in Qt 5.5. */ void QFileDialog::setDirectory(const QString &directory) { diff --git a/src/widgets/dialogs/qfileinfogatherer.cpp b/src/widgets/dialogs/qfileinfogatherer.cpp index df07de7975..7329019a87 100644 --- a/src/widgets/dialogs/qfileinfogatherer.cpp +++ b/src/widgets/dialogs/qfileinfogatherer.cpp @@ -185,6 +185,8 @@ void QFileInfoGatherer::removePath(const QString &path) #ifndef QT_NO_FILESYSTEMWATCHER QMutexLocker locker(&mutex); watcher->removePath(path); +#else + Q_UNUSED(path); #endif } diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index 04238f242a..4859231d95 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -544,7 +544,7 @@ QModelIndex QFileSystemModel::parent(const QModelIndex &index) const QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(index); Q_ASSERT(indexNode != 0); - QFileSystemModelPrivate::QFileSystemNode *parentNode = (indexNode ? indexNode->parent : 0); + QFileSystemModelPrivate::QFileSystemNode *parentNode = indexNode->parent; if (parentNode == 0 || parentNode == &d->root) return QModelIndex(); @@ -653,10 +653,12 @@ int QFileSystemModel::columnCount(const QModelIndex &parent) const */ QVariant QFileSystemModel::myComputer(int role) const { +#ifndef QT_NO_FILESYSTEMWATCHER Q_D(const QFileSystemModel); +#endif switch (role) { case Qt::DisplayRole: - return d->myComputer(); + return QFileSystemModelPrivate::myComputer(); #ifndef QT_NO_FILESYSTEMWATCHER case Qt::DecorationRole: return d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Computer); diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp index 701fea1c03..a4b37f360b 100644 --- a/src/widgets/dialogs/qwizard_win.cpp +++ b/src/widgets/dialogs/qwizard_win.cpp @@ -361,6 +361,36 @@ bool QVistaHelper::setDWMTitleBar(TitleBarChangeType type) Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &); +static LOGFONT getCaptionLogFont(HANDLE hTheme) +{ + LOGFONT result = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0 } }; + + if (!hTheme || FAILED(pGetThemeSysFont(hTheme, WIZ_TMT_CAPTIONFONT, &result))) { + NONCLIENTMETRICS ncm; + ncm.cbSize = sizeof(NONCLIENTMETRICS); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, false); + result = ncm.lfMessageFont; + } + return result; +} + +static bool getCaptionQFont(int dpi, QFont *result) +{ + if (!pOpenThemeData) + return false; + const HANDLE hTheme = + pOpenThemeData(QApplicationPrivate::getHWNDForWidget(QApplication::desktop()), L"WINDOW"); + if (!hTheme) + return false; + // Call into QWindowsNativeInterface to convert the LOGFONT into a QFont. + const LOGFONT logFont = getCaptionLogFont(hTheme); + QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface(); + return ni && QMetaObject::invokeMethod(ni, "logFontToQFont", Qt::DirectConnection, + Q_RETURN_ARG(QFont, *result), + Q_ARG(const void *, &logFont), + Q_ARG(int, dpi)); +} + void QVistaHelper::drawTitleBar(QPainter *painter) { Q_ASSERT(backButton_); @@ -378,7 +408,9 @@ void QVistaHelper::drawTitleBar(QPainter *painter) const int verticalCenter = (btnTop + btnHeight / 2) - 1; const QString text = wizard->window()->windowTitle(); - const QFont font = QApplication::font("QMdiSubWindowTitleBar"); + QFont font; + if (!isWindow || !getCaptionQFont(wizard->logicalDpiY() * wizard->devicePixelRatio(), &font)) + font = QApplication::font("QMdiSubWindowTitleBar"); const QFontMetrics fontMetrics(font); const QRect brect = fontMetrics.boundingRect(text); int textHeight = brect.height(); @@ -649,19 +681,6 @@ bool QVistaHelper::eventFilter(QObject *obj, QEvent *event) return false; } -HFONT QVistaHelper::getCaptionFont(HANDLE hTheme) -{ - LOGFONT lf = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0 } }; - - if (!hTheme || FAILED(pGetThemeSysFont(hTheme, WIZ_TMT_CAPTIONFONT, &lf))) { - NONCLIENTMETRICS ncm; - ncm.cbSize = sizeof(NONCLIENTMETRICS); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, false); - lf = ncm.lfMessageFont; - } - return CreateFontIndirect(&lf); -} - // Return a HDC for the wizard along with the transformation if the // wizard is a child window. HDC QVistaHelper::backingStoreDC(const QWidget *wizard, QPoint *offset) @@ -713,7 +732,8 @@ bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const Q bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0); // Set up the DC - HFONT hCaptionFont = getCaptionFont(hTheme); + const LOGFONT captionLogFont = getCaptionLogFont(hTheme); + const HFONT hCaptionFont = CreateFontIndirect(&captionLogFont); HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp); HFONT hOldFont = (HFONT)SelectObject(dcMem, (HGDIOBJ) hCaptionFont); diff --git a/src/widgets/dialogs/qwizard_win_p.h b/src/widgets/dialogs/qwizard_win_p.h index 8c36472bee..84b795d506 100644 --- a/src/widgets/dialogs/qwizard_win_p.h +++ b/src/widgets/dialogs/qwizard_win_p.h @@ -105,7 +105,6 @@ public: static HDC backingStoreDC(const QWidget *wizard, QPoint *offset); private: - static HFONT getCaptionFont(HANDLE hTheme); HWND wizardHWND() const; bool drawTitleText(QPainter *painter, const QString &text, const QRect &rect, HDC hdc); static bool drawBlackRect(const QRect &rect, HDC hdc); diff --git a/src/widgets/graphicsview/qgraphicsscene.h b/src/widgets/graphicsview/qgraphicsscene.h index b025730bb1..68382bf498 100644 --- a/src/widgets/graphicsview/qgraphicsscene.h +++ b/src/widgets/graphicsview/qgraphicsscene.h @@ -282,6 +282,10 @@ protected: QWidget *widget = 0); protected Q_SLOTS: + // ### Qt 6: make unconditional +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + virtual +#endif bool focusNextPrevChild(bool next); Q_SIGNALS: diff --git a/src/widgets/graphicsview/qgraphicswidget_p.cpp b/src/widgets/graphicsview/qgraphicswidget_p.cpp index 402d54d2d8..e9ab6dffec 100644 --- a/src/widgets/graphicsview/qgraphicswidget_p.cpp +++ b/src/widgets/graphicsview/qgraphicswidget_p.cpp @@ -64,9 +64,7 @@ void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFl adjustWindowFlags(&wFlags); windowFlags = wFlags; - if (parentItem) - setParentItemHelper(parentItem, 0, 0); - + q->setParentItem(parentItem); q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::DefaultType)); q->setGraphicsItem(q); diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index b792228312..016c50436b 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -168,8 +168,20 @@ public: QModelIndex index; int col = -1; int row = -1; + const QMimeData *mime = event->mimeData(); + + // Drag enter event shall always be accepted, if mime type and action match. + // Whether the data can actually be dropped will be checked in drag move. + if (event->type() == QEvent::DragEnter) { + const QStringList modelTypes = model->mimeTypes(); + for (int i = 0; i < modelTypes.count(); ++i) + if (mime->hasFormat(modelTypes.at(i)) + && (event->dropAction() & model->supportedDropActions())) + return true; + } + if (dropOn(event, &row, &col, &index)) { - return model->canDropMimeData(event->mimeData(), + return model->canDropMimeData(mime, dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(), row, col, index); } diff --git a/src/widgets/itemviews/qcolumnview_p.h b/src/widgets/itemviews/qcolumnview_p.h index ed30b5f085..0c0bdb5d1f 100644 --- a/src/widgets/itemviews/qcolumnview_p.h +++ b/src/widgets/itemviews/qcolumnview_p.h @@ -89,6 +89,16 @@ public: QAbstractScrollArea::resizeEvent(event); } + void scrollContentsBy(int dx, int dy) Q_DECL_OVERRIDE + { + if (!previewWidget) + return; + scrollDirtyRegion(dx, dy); + viewport()->scroll(dx, dy); + + QAbstractItemView::scrollContentsBy(dx, dy); + } + QRect visualRect(const QModelIndex &) const Q_DECL_OVERRIDE { return QRect(); diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 66ff472724..bca315f80b 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -1879,13 +1879,13 @@ void QHeaderView::sectionsInserted(const QModelIndex &parent, // insert sections into hiddenSectionSize QHash newHiddenSectionSize; // from logical index to section size - for (int i = 0; i < logicalFirst; ++i) - if (isSectionHidden(i)) - newHiddenSectionSize[i] = d->hiddenSectionSize[i]; - for (int j = logicalLast + 1; j < d->sectionCount(); ++j) - if (isSectionHidden(j)) - newHiddenSectionSize[j] = d->hiddenSectionSize[j - insertCount]; - d->hiddenSectionSize = newHiddenSectionSize; + for (QHash::const_iterator it = d->hiddenSectionSize.cbegin(), + end = d->hiddenSectionSize.cend(); it != end; ++it) { + const int oldIndex = it.key(); + const int newIndex = (oldIndex < logicalFirst) ? oldIndex : oldIndex + insertCount; + newHiddenSectionSize[newIndex] = it.value(); + } + d->hiddenSectionSize.swap(newHiddenSectionSize); d->doDelayedResizeSections(); emit sectionCountChanged(oldCount, count()); diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index 29a6629bcd..9b07564db9 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1877,8 +1877,17 @@ void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step) const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded && qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded; - if (bothScrollBarsAuto && contentsSize.width() - qq->verticalScrollBar()->width() <= viewport()->width() - && contentsSize.height() - qq->horizontalScrollBar()->height() <= viewport()->height()) { + const QSize viewportSize(viewport()->width() + (qq->verticalScrollBar()->maximum() > 0 ? qq->verticalScrollBar()->width() : 0), + viewport()->height() + (qq->horizontalScrollBar()->maximum() > 0 ? qq->horizontalScrollBar()->height() : 0)); + + bool verticalWantsToShow = contentsSize.height() > viewportSize.height(); + bool horizontalWantsToShow; + if (verticalWantsToShow) + horizontalWantsToShow = contentsSize.width() > viewportSize.width() - qq->verticalScrollBar()->width(); + else + horizontalWantsToShow = contentsSize.width() > viewportSize.width(); + + if (bothScrollBarsAuto && !horizontalWantsToShow) { // break the infinite loop described above by setting the range to 0, 0. // QAbstractScrollArea will then hide the scroll bar for us horizontalScrollBar()->setRange(0, 0); @@ -1899,8 +1908,17 @@ void QCommonListViewBase::updateVerticalScrollBar(const QSize &step) const bool bothScrollBarsAuto = qq->verticalScrollBarPolicy() == Qt::ScrollBarAsNeeded && qq->horizontalScrollBarPolicy() == Qt::ScrollBarAsNeeded; - if (bothScrollBarsAuto && contentsSize.width() - qq->verticalScrollBar()->width() <= viewport()->width() - && contentsSize.height() - qq->horizontalScrollBar()->height() <= viewport()->height()) { + const QSize viewportSize(viewport()->width() + (qq->verticalScrollBar()->maximum() > 0 ? qq->verticalScrollBar()->width() : 0), + viewport()->height() + (qq->horizontalScrollBar()->maximum() > 0 ? qq->horizontalScrollBar()->height() : 0)); + + bool horizontalWantsToShow = contentsSize.width() > viewportSize.width(); + bool verticalWantsToShow; + if (horizontalWantsToShow) + verticalWantsToShow = contentsSize.height() > viewportSize.height() - qq->horizontalScrollBar()->height(); + else + verticalWantsToShow = contentsSize.height() > viewportSize.height(); + + if (bothScrollBarsAuto && !verticalWantsToShow) { // break the infinite loop described above by setting the range to 0, 0. // QAbstractScrollArea will then hide the scroll bar for us verticalScrollBar()->setRange(0, 0); diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index 43db43fcd4..9b3e270fdd 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -3658,6 +3658,7 @@ void QTreeViewPrivate::updateScrollBars() if (!viewportSize.isValid()) viewportSize = QSize(0, 0); + executePostedLayout(); if (viewItems.isEmpty()) { q->doItemsLayout(); } diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri index 88c1e2595b..21a982f349 100644 --- a/src/widgets/kernel/kernel.pri +++ b/src/widgets/kernel/kernel.pri @@ -49,6 +49,7 @@ SOURCES += \ kernel/qlayoutengine.cpp \ kernel/qlayoutitem.cpp \ kernel/qshortcut.cpp \ + kernel/qsizepolicy.cpp \ kernel/qstackedlayout.cpp \ kernel/qtooltip.cpp \ kernel/qwhatsthis.cpp \ diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 401fb47dc8..f457993168 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -4272,15 +4272,16 @@ void QApplicationPrivate::cleanupMultitouch_sys() { } -QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos) +QWidget *QApplicationPrivate::findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint) { + const QPointF screenPos = touchPoint.screenPos(); int closestTouchPointId = -1; QObject *closestTarget = 0; qreal closestDistance = qreal(0.); QHash::const_iterator it = activeTouchPoints.constBegin(), ite = activeTouchPoints.constEnd(); while (it != ite) { - if (it.key().device == device) { + if (it.key().device == device && it.key().touchPointId != touchPoint.id()) { const QTouchEvent::TouchPoint &touchPoint = it->touchPoint; qreal dx = screenPos.x() - touchPoint.screenPos().x(); qreal dy = screenPos.y() - touchPoint.screenPos().y(); @@ -4336,7 +4337,7 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, } if (device->type() == QTouchDevice::TouchScreen) { - QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint.screenPos()); + QWidget *closestWidget = d->findClosestTouchPointTarget(device, touchPoint); QWidget *widget = static_cast(target.data()); if (closestWidget && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { @@ -4356,8 +4357,10 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, #ifdef Q_OS_OSX // Single-touch events are normally not sent unless WA_TouchPadAcceptSingleTouchEvents is set. - // In Qt 4 this check was in OS X-only coode. That behavior is preserved here by the #ifdef. - if (touchPoints.count() == 1 && !targetWidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents)) + // In Qt 4 this check was in OS X-only code. That behavior is preserved here by the #ifdef. + if (touchPoints.count() == 1 + && device->type() == QTouchDevice::TouchPad + && !targetWidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents)) continue; #endif @@ -4373,7 +4376,7 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, QHash::ConstIterator it = widgetsNeedingEvents.constBegin(); const QHash::ConstIterator end = widgetsNeedingEvents.constEnd(); for (; it != end; ++it) { - QWidget *widget = it.key(); + const QPointer widget = it.key(); if (!QApplicationPrivate::tryModalHelper(widget, 0)) continue; @@ -4413,7 +4416,8 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, // has been implicitly accepted and continue to send touch events if (QApplication::sendSpontaneousEvent(widget, &touchEvent) && touchEvent.isAccepted()) { accepted = true; - widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent); + if (!widget.isNull()) + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent); } break; } diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 46359d7940..ba8d7ff63c 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -280,7 +280,7 @@ public: void initializeMultitouch_sys(); void cleanupMultitouch(); void cleanupMultitouch_sys(); - QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QPointF &screenPos); + QWidget *findClosestTouchPointTarget(QTouchDevice *device, const QTouchEvent::TouchPoint &touchPoint); void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); void removeTouchPoint(int touchPointId); static bool translateRawTouchEvent(QWidget *widget, diff --git a/src/widgets/kernel/qgesture.cpp b/src/widgets/kernel/qgesture.cpp index 713a019cc3..7b7d465070 100644 --- a/src/widgets/kernel/qgesture.cpp +++ b/src/widgets/kernel/qgesture.cpp @@ -36,7 +36,7 @@ #include "private/qstandardgestures_p.h" #include "qgraphicsview.h" -#include +#include #ifndef QT_NO_GESTURES QT_BEGIN_NAMESPACE @@ -1091,9 +1091,12 @@ QPointF QGestureEvent::mapToGraphicsScene(const QPointF &gesturePoint) const static void formatGestureHeader(QDebug d, const char *className, const QGesture *gesture) { - d << className << "(state=" << gesture->state(); - if (gesture->hasHotSpot()) - d << ",hotSpot=" << gesture->hotSpot(); + d << className << "(state="; + QtDebugUtils::formatQEnum(d, gesture->state()); + if (gesture->hasHotSpot()) { + d << ",hotSpot="; + QtDebugUtils::formatQPoint(d, gesture->hotSpot()); + } } Q_WIDGETS_EXPORT QDebug operator<<(QDebug d, const QGesture *gesture) @@ -1103,31 +1106,42 @@ Q_WIDGETS_EXPORT QDebug operator<<(QDebug d, const QGesture *gesture) switch (gesture->gestureType()) { case Qt::TapGesture: formatGestureHeader(d, "QTapGesture", gesture); - d << ",position=" << static_cast(gesture)->position() << ')'; + d << ",position="; + QtDebugUtils::formatQPoint(d, static_cast(gesture)->position()); + d << ')'; break; case Qt::TapAndHoldGesture: { const QTapAndHoldGesture *tap = static_cast(gesture); formatGestureHeader(d, "QTapAndHoldGesture", tap); - d << ",position=" << tap->position() << ",timeout=" << tap->timeout() << ')'; + d << ",position="; + QtDebugUtils::formatQPoint(d, tap->position()); + d << ",timeout=" << tap->timeout() << ')'; } break; case Qt::PanGesture: { const QPanGesture *pan = static_cast(gesture); formatGestureHeader(d, "QPanGesture", pan); - d << ",lastOffset=" << pan->lastOffset() << ",offset=" << pan->offset() - << ",acceleration=" << pan->acceleration() - << ",delta=" << pan->delta() << ')'; + d << ",lastOffset="; + QtDebugUtils::formatQPoint(d, pan->lastOffset()); + d << pan->lastOffset(); + d << ",offset="; + QtDebugUtils::formatQPoint(d, pan->offset()); + d << ",acceleration=" << pan->acceleration() << ",delta="; + QtDebugUtils::formatQPoint(d, pan->delta()); + d << ')'; } break; case Qt::PinchGesture: { const QPinchGesture *pinch = static_cast(gesture); formatGestureHeader(d, "QPinchGesture", pinch); d << ",totalChangeFlags=" << pinch->totalChangeFlags() - << ",changeFlags=" << pinch->changeFlags() - << ",startCenterPoint=" << pinch->startCenterPoint() - << ",lastCenterPoint=" << pinch->lastCenterPoint() - << ",centerPoint=" << pinch->centerPoint() - << ",totalScaleFactor=" << pinch->totalScaleFactor() + << ",changeFlags=" << pinch->changeFlags() << ",startCenterPoint="; + QtDebugUtils::formatQPoint(d, pinch->startCenterPoint()); + d << ",lastCenterPoint="; + QtDebugUtils::formatQPoint(d, pinch->lastCenterPoint()); + d << ",centerPoint="; + QtDebugUtils::formatQPoint(d, pinch->centerPoint()); + d << ",totalScaleFactor=" << pinch->totalScaleFactor() << ",lastScaleFactor=" << pinch->lastScaleFactor() << ",scaleFactor=" << pinch->scaleFactor() << ",totalRotationAngle=" << pinch->totalRotationAngle() @@ -1138,9 +1152,11 @@ Q_WIDGETS_EXPORT QDebug operator<<(QDebug d, const QGesture *gesture) case Qt::SwipeGesture: { const QSwipeGesture *swipe = static_cast(gesture); formatGestureHeader(d, "QSwipeGesture", swipe); - d << ",horizontalDirection=" << swipe->horizontalDirection() - << ",verticalDirection=" << swipe->verticalDirection() - << ",swipeAngle=" << swipe->swipeAngle() << ')'; + d << ",horizontalDirection="; + QtDebugUtils::formatQEnum(d, swipe->horizontalDirection()); + d << ",verticalDirection="; + QtDebugUtils::formatQEnum(d, swipe->verticalDirection()); + d << ",swipeAngle=" << swipe->swipeAngle() << ')'; } break; default: diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index dcacea4777..e74f17b6f7 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -1470,85 +1470,4 @@ QSize QLayout::closestAcceptableSize(const QWidget *widget, const QSize &size) return result; } -void QSizePolicy::setControlType(ControlType type) -{ - /* - The control type is a flag type, with values 0x1, 0x2, 0x4, 0x8, 0x10, - etc. In memory, we pack it onto the available bits (CTSize) in - setControlType(), and unpack it here. - - Example: - - 0x00000001 maps to 0 - 0x00000002 maps to 1 - 0x00000004 maps to 2 - 0x00000008 maps to 3 - etc. - */ - - int i = 0; - while (true) { - if (type & (0x1 << i)) { - bits.ctype = i; - return; - } - ++i; - } -} - -QSizePolicy::ControlType QSizePolicy::controlType() const -{ - return QSizePolicy::ControlType(1 << bits.ctype); -} - -#ifndef QT_NO_DATASTREAM - -/*! - \relates QSizePolicy - \since 4.2 - - Writes the size \a policy to the data stream \a stream. - - \sa{Serializing Qt Data Types}{Format of the QDataStream operators} -*/ -QDataStream &operator<<(QDataStream &stream, const QSizePolicy &policy) -{ - // The order here is for historical reasons. (compatibility with Qt4) - quint32 data = (policy.bits.horPolicy | // [0, 3] - policy.bits.verPolicy << 4 | // [4, 7] - policy.bits.hfw << 8 | // [8] - policy.bits.ctype << 9 | // [9, 13] - policy.bits.wfh << 14 | // [14] - policy.bits.retainSizeWhenHidden << 15 | // [15] - policy.bits.verStretch << 16 | // [16, 23] - policy.bits.horStretch << 24); // [24, 31] - return stream << data; -} - -#define VALUE_OF_BITS(data, bitstart, bitcount) ((data >> bitstart) & ((1 << bitcount) -1)) - -/*! - \relates QSizePolicy - \since 4.2 - - Reads the size \a policy from the data stream \a stream. - - \sa{Serializing Qt Data Types}{Format of the QDataStream operators} -*/ -QDataStream &operator>>(QDataStream &stream, QSizePolicy &policy) -{ - quint32 data; - stream >> data; - policy.bits.horPolicy = VALUE_OF_BITS(data, 0, 4); - policy.bits.verPolicy = VALUE_OF_BITS(data, 4, 4); - policy.bits.hfw = VALUE_OF_BITS(data, 8, 1); - policy.bits.ctype = VALUE_OF_BITS(data, 9, 5); - policy.bits.wfh = VALUE_OF_BITS(data, 14, 1); - policy.bits.retainSizeWhenHidden = VALUE_OF_BITS(data, 15, 1); - policy.bits.verStretch = VALUE_OF_BITS(data, 16, 8); - policy.bits.horStretch = VALUE_OF_BITS(data, 24, 8); - return stream; -} -#endif // QT_NO_DATASTREAM - QT_END_NAMESPACE diff --git a/src/widgets/kernel/qlayoutitem.cpp b/src/widgets/kernel/qlayoutitem.cpp index b21925e1d4..21f4c9a221 100644 --- a/src/widgets/kernel/qlayoutitem.cpp +++ b/src/widgets/kernel/qlayoutitem.cpp @@ -34,7 +34,6 @@ #include "qlayout.h" #include "qapplication.h" -#include "qdebug.h" #include "qlayoutengine_p.h" #include "qmenubar.h" #include "qtoolbar.h" @@ -67,14 +66,6 @@ inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size) return toLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size(); } -/*! - Returns a QVariant storing this QSizePolicy. -*/ -QSizePolicy::operator QVariant() const -{ - return QVariant(QVariant::SizePolicy, this); -} - /*! \class QLayoutItem \brief The QLayoutItem class provides an abstract item that a @@ -847,14 +838,4 @@ int QWidgetItemV2::heightForWidth(int width) const return height; } -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug dbg, const QSizePolicy &p) -{ - QDebugStateSaver saver(dbg); - dbg.nospace() << "QSizePolicy(horizontalPolicy = " << p.horizontalPolicy() - << ", verticalPolicy = " << p.verticalPolicy() << ')'; - return dbg; -} -#endif - QT_END_NAMESPACE diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index d4d23604a3..9bfdc62e60 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -104,6 +104,12 @@ QT_BEGIN_NAMESPACE non-sharable. To overcome this issue, prefer using QSurfaceFormat::setDefaultFormat() instead of setFormat(). + \note Calling QSurfaceFormat::setDefaultFormat() before constructing + the QApplication instance is mandatory on some platforms (for example, + OS X) when an OpenGL core profile context is requested. This is to + ensure that resource sharing between contexts stays functional as all + internal contexts are created using the correct version and profile. + \section1 Painting Techniques As described above, subclass QOpenGLWidget to render pure 3D content in the @@ -739,6 +745,7 @@ void QOpenGLWidgetPrivate::initialize() QScopedPointer ctx(new QOpenGLContext); ctx->setShareContext(shareContext); ctx->setFormat(requestedFormat); + ctx->setScreen(shareContext->screen()); if (!ctx->create()) { qWarning("QOpenGLWidget: Failed to create context"); return; @@ -762,6 +769,7 @@ void QOpenGLWidgetPrivate::initialize() // in QQuickWidget, use a dedicated QOffscreenSurface. surface = new QOffscreenSurface; surface->setFormat(ctx->format()); + surface->setScreen(ctx->screen()); surface->create(); if (!ctx->makeCurrent(surface)) { diff --git a/src/widgets/kernel/qsizepolicy.qdoc b/src/widgets/kernel/qsizepolicy.cpp similarity index 75% rename from src/widgets/kernel/qsizepolicy.qdoc rename to src/widgets/kernel/qsizepolicy.cpp index e84412bc46..1476b4c5d7 100644 --- a/src/widgets/kernel/qsizepolicy.qdoc +++ b/src/widgets/kernel/qsizepolicy.cpp @@ -3,9 +3,9 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the documentation of the Qt Toolkit. +** This file is part of the QtWidgets module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:FDL$ +** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,17 +14,31 @@ ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: http://www.gnu.org/copyleft/fdl.html. +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "qsizepolicy.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + /*! \class QSizePolicy \brief The QSizePolicy class is a layout attribute describing horizontal @@ -207,15 +221,18 @@ */ /*! - \fn ControlType QSizePolicy::controlType() const \since 4.3 Returns the control type associated with the widget for which this size policy applies. */ +QSizePolicy::ControlType QSizePolicy::controlType() const +{ + return QSizePolicy::ControlType(1 << bits.ctype); +} + /*! - \fn void QSizePolicy::setControlType(ControlType type) \since 4.3 Sets the control type associated with the widget for which this @@ -230,6 +247,31 @@ \sa QStyle::layoutSpacing() */ +void QSizePolicy::setControlType(ControlType type) +{ + /* + The control type is a flag type, with values 0x1, 0x2, 0x4, 0x8, 0x10, + etc. In memory, we pack it onto the available bits (CTSize) in + setControlType(), and unpack it here. + + Example: + + 0x00000001 maps to 0 + 0x00000002 maps to 1 + 0x00000004 maps to 2 + 0x00000008 maps to 3 + etc. + */ + + int i = 0; + while (true) { + if (type & (0x1 << i)) { + bits.ctype = i; + return; + } + ++i; + } +} /*! \fn void QSizePolicy::setHeightForWidth(bool dependent) @@ -344,7 +386,8 @@ \fn void QSizePolicy::retainSizeWhenHidden() const \since 5.2 - Returns if the layout should retain the widgets size when it is hidden. This is by default false. + Returns whether the layout should retain the widget's size when it is hidden. + This is \c false by default. \sa setRetainSizeWhenHidden() */ @@ -353,8 +396,8 @@ \fn void QSizePolicy::setRetainSizeWhenHidden(bool retainSize) \since 5.2 - Set if a layout should retain the widgets size when it is hidden. - If \a retainSize is true the layout will not be changed by hiding the widget. + Sets whether a layout should retain the widget's size when it is hidden. + If \a retainSize is \c true, the layout will not be changed by hiding the widget. \sa retainSizeWhenHidden() */ @@ -385,3 +428,72 @@ \sa setControlType(), controlType() */ +/*! + Returns a QVariant storing this QSizePolicy. +*/ +QSizePolicy::operator QVariant() const +{ + return QVariant(QVariant::SizePolicy, this); +} + +#ifndef QT_NO_DATASTREAM + +/*! + \relates QSizePolicy + \since 4.2 + + Writes the size \a policy to the data stream \a stream. + + \sa{Serializing Qt Data Types}{Format of the QDataStream operators} +*/ +QDataStream &operator<<(QDataStream &stream, const QSizePolicy &policy) +{ + // The order here is for historical reasons. (compatibility with Qt4) + quint32 data = (policy.bits.horPolicy | // [0, 3] + policy.bits.verPolicy << 4 | // [4, 7] + policy.bits.hfw << 8 | // [8] + policy.bits.ctype << 9 | // [9, 13] + policy.bits.wfh << 14 | // [14] + policy.bits.retainSizeWhenHidden << 15 | // [15] + policy.bits.verStretch << 16 | // [16, 23] + policy.bits.horStretch << 24); // [24, 31] + return stream << data; +} + +#define VALUE_OF_BITS(data, bitstart, bitcount) ((data >> bitstart) & ((1 << bitcount) -1)) + +/*! + \relates QSizePolicy + \since 4.2 + + Reads the size \a policy from the data stream \a stream. + + \sa{Serializing Qt Data Types}{Format of the QDataStream operators} +*/ +QDataStream &operator>>(QDataStream &stream, QSizePolicy &policy) +{ + quint32 data; + stream >> data; + policy.bits.horPolicy = VALUE_OF_BITS(data, 0, 4); + policy.bits.verPolicy = VALUE_OF_BITS(data, 4, 4); + policy.bits.hfw = VALUE_OF_BITS(data, 8, 1); + policy.bits.ctype = VALUE_OF_BITS(data, 9, 5); + policy.bits.wfh = VALUE_OF_BITS(data, 14, 1); + policy.bits.retainSizeWhenHidden = VALUE_OF_BITS(data, 15, 1); + policy.bits.verStretch = VALUE_OF_BITS(data, 16, 8); + policy.bits.horStretch = VALUE_OF_BITS(data, 24, 8); + return stream; +} +#endif // QT_NO_DATASTREAM + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QSizePolicy &p) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "QSizePolicy(horizontalPolicy = " << p.horizontalPolicy() + << ", verticalPolicy = " << p.verticalPolicy() << ')'; + return dbg; +} +#endif + +QT_END_NAMESPACE diff --git a/src/widgets/kernel/qsizepolicy.h b/src/widgets/kernel/qsizepolicy.h index 2376a2c644..6cd511f513 100644 --- a/src/widgets/kernel/qsizepolicy.h +++ b/src/widgets/kernel/qsizepolicy.h @@ -112,7 +112,7 @@ public: bool operator==(const QSizePolicy& s) const { return data == s.data; } bool operator!=(const QSizePolicy& s) const { return data != s.data; } - operator QVariant() const; // implemented in qlayoutitem.cpp + operator QVariant() const; int horizontalStretch() const { return static_cast(bits.horStretch); } int verticalStretch() const { return static_cast(bits.verStretch); } @@ -155,7 +155,6 @@ Q_DECLARE_TYPEINFO(QSizePolicy, Q_PRIMITIVE_TYPE); Q_DECLARE_OPERATORS_FOR_FLAGS(QSizePolicy::ControlTypes) #ifndef QT_NO_DATASTREAM -// implemented in qlayout.cpp Q_WIDGETS_EXPORT QDataStream &operator<<(QDataStream &, const QSizePolicy &); Q_WIDGETS_EXPORT QDataStream &operator>>(QDataStream &, QSizePolicy &); #endif diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index b49fd9b3b6..b4943bbe05 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -4859,7 +4859,7 @@ void QWidget::unsetLayoutDirection() \fn QFontMetrics QWidget::fontMetrics() const Returns the font metrics for the widget's current font. - Equivalent to QFontMetrics(widget->font()). + Equivalent to \c QFontMetrics(widget->font()). \sa font(), fontInfo(), setFont() */ @@ -4868,7 +4868,7 @@ void QWidget::unsetLayoutDirection() \fn QFontInfo QWidget::fontInfo() const Returns the font info for the widget's current font. - Equivalent to QFontInto(widget->font()). + Equivalent to \c QFontInfo(widget->font()). \sa font(), fontMetrics(), setFont() */ @@ -7334,6 +7334,8 @@ bool QWidget::restoreGeometry(const QByteArray &geometry) stream >> restoredScreenWidth; const QDesktopWidget * const desktop = QApplication::desktop(); + if (restoredScreenNumber >= desktop->numScreens()) + restoredScreenNumber = desktop->primaryScreen(); const qreal screenWidthF = qreal(desktop->screenGeometry(restoredScreenNumber).width()); // Sanity check bailing out when large variations of screen sizes occur due to // high DPI scaling or different levels of DPI awareness. @@ -7361,9 +7363,6 @@ bool QWidget::restoreGeometry(const QByteArray &geometry) .expandedTo(d_func()->adjustedSize())); } - if (restoredScreenNumber >= desktop->numScreens()) - restoredScreenNumber = desktop->primaryScreen(); - const QRect availableGeometry = desktop->availableGeometry(restoredScreenNumber); // Modify the restored geometry if we are about to restore to coordinates @@ -12093,6 +12092,7 @@ QOpenGLContext *QWidgetPrivate::shareContext() const QOpenGLContext *ctx = new QOpenGLContext; ctx->setShareContext(qt_gl_global_share_context()); ctx->setFormat(extra->topextra->window->format()); + ctx->setScreen(extra->topextra->window->screen()); ctx->create(); that->extra->topextra->shareContext = ctx; } diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 485cf82078..d1070839fa 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -962,7 +962,8 @@ static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatfo QPlatformTextureList::Flags flags = 0; if (widget->testAttribute(Qt::WA_AlwaysStackOnTop)) flags |= QPlatformTextureList::StacksOnTop; - widgetTextures->appendTexture(widget, wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()), flags); + const QRect rect(widget->mapTo(tlw, QPoint()), widget->size()); + widgetTextures->appendTexture(widget, wd->textureId(), rect, wd->clipRect(), flags); } for (int i = 0; i < wd->children.size(); ++i) { @@ -1156,7 +1157,7 @@ void QWidgetBackingStore::doSync() #ifndef QT_NO_OPENGL if (widgetTextures && widgetTextures->count()) { for (int i = 0; i < widgetTextures->count(); ++i) { - QWidget *w = widgetTextures->widget(i); + QWidget *w = static_cast(widgetTextures->source(i)); if (dirtyRenderToTextureWidgets.contains(w)) { const QRect rect = widgetTextures->geometry(i); // mapped to the tlw already dirty += rect; diff --git a/src/widgets/styles/qcommonstylepixmaps_p.h b/src/widgets/styles/qcommonstylepixmaps_p.h index 471903e927..8075256158 100644 --- a/src/widgets/styles/qcommonstylepixmaps_p.h +++ b/src/widgets/styles/qcommonstylepixmaps_p.h @@ -348,7 +348,7 @@ static const char * const qt_unshade_xpm[] = { "..........", ".........."}; -static const char * dock_widget_close_xpm[] = { +static const char * const dock_widget_close_xpm[] = { "8 8 2 1", "# c #000000", ". c None", diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 862a4302f3..1849331b79 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -2368,8 +2368,8 @@ QDebug operator<<(QDebug debug, QStyle::State state) return operator<< (debug, state); # else Q_UNUSED(state); -# endif return debug; +# endif } # endif // !QT_NO_DEBUG_STREAM #endif // QT_VERSION < QT_VERSION_CHECK(6,0,0) diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 86b5632d2e..40b8aaae9a 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -586,7 +586,7 @@ public: }; /////////////////////////////////////////////////////////////////////////////////////////// -static const char *knownStyleHints[] = { +static const char *const knownStyleHints[] = { "activate-on-singleclick", "alignment", "arrow-keys-navigate-into-children", diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 40597a41f3..db8a649931 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -299,8 +299,8 @@ void QWindowsStyle::polish(QPalette &pal) int QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *, const QWidget *widget) { - switch (pm) { #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) + switch (pm) { case QStyle::PM_DockWidgetFrameWidth: # ifndef Q_OS_WINCE return GetSystemMetrics(SM_CXFRAME); @@ -337,13 +337,14 @@ int QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const # else return GetSystemMetrics(SM_CYDLGFRAME); # endif -#else - Q_UNUSED(widget) -#endif // Q_OS_WIN default: break; } +#else // Q_OS_WIN && !Q_OS_WINRT + Q_UNUSED(pm); + Q_UNUSED(widget); +#endif return QWindowsStylePrivate::InvalidMetric; } diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index f715d93298..daa8ab12a9 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -250,8 +250,6 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt int state = option->state; if (!QWindowsVistaStylePrivate::useVista()) { - foreach (const QObject *target, d->animationTargets()) - d->stopAnimation(target); QWindowsStyle::drawPrimitive(element, option, painter, widget); return; } @@ -810,8 +808,6 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption QWindowsVistaStylePrivate *d = const_cast(d_func()); if (!QWindowsVistaStylePrivate::useVista()) { - foreach (const QObject *target, d->animationTargets()) - d->stopAnimation(target); QWindowsStyle::drawControl(element, option, painter, widget); return; } @@ -1494,8 +1490,6 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle { QWindowsVistaStylePrivate *d = const_cast(d_func()); if (!QWindowsVistaStylePrivate::useVista()) { - foreach (const QObject *target, d->animationTargets()) - d->stopAnimation(target); QWindowsStyle::drawComplexControl(control, option, painter, widget); return; } diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 76f923904d..ef80e359df 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -3034,7 +3034,7 @@ void QComboBoxPrivate::showPopupFromMouseEvent(QMouseEvent *e) QStyle::SubControl sc = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, e->pos(), q); if (e->button() == Qt::LeftButton - && sc != QStyle::SC_None + && !(sc == QStyle::SC_None && e->type() == QEvent::MouseButtonRelease) && (sc == QStyle::SC_ComboBoxArrow || !q->isEditable()) && !viewContainer()->isVisible()) { if (sc == QStyle::SC_ComboBoxArrow) diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp index b1749fa5d3..a8da78a025 100644 --- a/src/widgets/widgets/qdatetimeedit.cpp +++ b/src/widgets/widgets/qdatetimeedit.cpp @@ -2316,9 +2316,9 @@ void QDateTimeEdit::paintEvent(QPaintEvent *event) QString QDateTimeEditPrivate::getAmPmText(AmPm ap, Case cs) const { if (ap == AmText) { - return (cs == UpperCase ? QDateTimeEdit::tr("AM") : QDateTimeEdit::tr("am")); + return (cs == UpperCase ? QDateTimeParser::tr("AM") : QDateTimeParser::tr("am")); } else { - return (cs == UpperCase ? QDateTimeEdit::tr("PM") : QDateTimeEdit::tr("pm")); + return (cs == UpperCase ? QDateTimeParser::tr("PM") : QDateTimeParser::tr("pm")); } } diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp index 237eb775b9..3e8c08f923 100644 --- a/src/widgets/widgets/qdialogbuttonbox.cpp +++ b/src/widgets/widgets/qdialogbuttonbox.cpp @@ -852,9 +852,19 @@ void QDialogButtonBoxPrivate::_q_handleButtonClicked() { Q_Q(QDialogButtonBox); if (QAbstractButton *button = qobject_cast(q->sender())) { + // Can't fetch this *after* emitting clicked, as clicked may destroy the button + // or change its role. Now changing the role is not possible yet, but arguably + // both clicked and accepted/rejected/etc. should be emitted "atomically" + // depending on whatever role the button had at the time of the click. + const QDialogButtonBox::ButtonRole buttonRole = q->buttonRole(button); + QPointer guard(q); + emit q->clicked(button); - switch (q->buttonRole(button)) { + if (!guard) + return; + + switch (buttonRole) { case QPlatformDialogHelper::AcceptRole: case QPlatformDialogHelper::YesRole: emit q->accepted(); diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index 6a41c3791f..ad3a92d35a 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -440,6 +440,10 @@ QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineE Q_Q(QLineEdit); if (!newAction) return 0; + if (!hasSideWidgets()) { // initial setup. + QObject::connect(q, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString))); + lastTextSize = q->text().size(); + } QWidget *w = 0; // Store flags about QWidgetAction here since removeAction() may be called from ~QAction, // in which a qobject_cast<> no longer works. @@ -456,10 +460,6 @@ QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineE toolButton->setDefaultAction(newAction); w = toolButton; } - if (!hasSideWidgets()) { // initial setup. - QObject::connect(q, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString))); - lastTextSize = q->text().size(); - } // If there is a 'before' action, it takes preference PositionIndexPair positionIndex = before ? findSideWidget(before) : PositionIndexPair(position, -1); SideWidgetEntryList &list = positionIndex.first == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets; diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h index 1ede07e4cb..4654262ea7 100644 --- a/src/widgets/widgets/qlineedit_p.h +++ b/src/widgets/widgets/qlineedit_p.h @@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE // QLineEditIconButton: This is a simple helper class that represents clickable icons that fade in with text -class QLineEditIconButton : public QToolButton +class Q_AUTOTEST_EXPORT QLineEditIconButton : public QToolButton { Q_OBJECT Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) diff --git a/src/widgets/widgets/qmacnativewidget_mac.h b/src/widgets/widgets/qmacnativewidget_mac.h index b27d877e8f..761e55656b 100644 --- a/src/widgets/widgets/qmacnativewidget_mac.h +++ b/src/widgets/widgets/qmacnativewidget_mac.h @@ -52,7 +52,6 @@ public: NSView *nativeView() const; protected: - void init(NSView *parentView); bool event(QEvent *ev); private: diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 19f6b78853..4403deda8e 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -183,7 +183,7 @@ void QMenuPrivate::setPlatformMenu(QPlatformMenu *menu) } // forward declare function -static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem* item); +static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu); void QMenuPrivate::syncPlatformMenu() { @@ -200,7 +200,7 @@ void QMenuPrivate::syncPlatformMenu() menuItem->setTag(reinterpret_cast(action)); QObject::connect(menuItem, SIGNAL(activated()), action, SLOT(trigger()), Qt::QueuedConnection); QObject::connect(menuItem, SIGNAL(hovered()), action, SIGNAL(hovered()), Qt::QueuedConnection); - copyActionToPlatformItem(action, menuItem); + copyActionToPlatformItem(action, menuItem, platformMenu.data()); platformMenu->insertMenuItem(menuItem, beforeItem); beforeItem = menuItem; } @@ -3104,7 +3104,7 @@ QMenu::timerEvent(QTimerEvent *e) } } -static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem* item) +static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem *item, QPlatformMenu *itemsMenu) { item->setText(action->text()); item->setIsSeparator(action->isSeparator()); @@ -3130,6 +3130,8 @@ static void copyActionToPlatformItem(const QAction *action, QPlatformMenuItem* i item->setEnabled(action->isEnabled()); if (action->menu()) { + if (!action->menu()->platformMenu()) + action->menu()->setPlatformMenu(itemsMenu->createSubMenu()); item->setMenu(action->menu()->platformMenu()); } else { item->setMenu(0); @@ -3184,7 +3186,7 @@ void QMenu::actionEvent(QActionEvent *e) menuItem->setTag(reinterpret_cast(e->action())); QObject::connect(menuItem, SIGNAL(activated()), e->action(), SLOT(trigger())); QObject::connect(menuItem, SIGNAL(hovered()), e->action(), SIGNAL(hovered())); - copyActionToPlatformItem(e->action(), menuItem); + copyActionToPlatformItem(e->action(), menuItem, d->platformMenu); QPlatformMenuItem* beforeItem = d->platformMenu->menuItemForTag(reinterpret_cast(e->before())); d->platformMenu->insertMenuItem(menuItem, beforeItem); } else if (e->type() == QEvent::ActionRemoved) { @@ -3194,7 +3196,7 @@ void QMenu::actionEvent(QActionEvent *e) } else if (e->type() == QEvent::ActionChanged) { QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast(e->action())); if (menuItem) { - copyActionToPlatformItem(e->action(), menuItem); + copyActionToPlatformItem(e->action(), menuItem, d->platformMenu); d->platformMenu->syncMenuItem(menuItem); } } diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 4659d9cf6c..1ad99bed9c 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1632,7 +1632,7 @@ QSize QMenuBar::sizeHint() const if(d->leftWidget) { QSize sz = d->leftWidget->sizeHint(); sz.rheight() += margin; - ret.expandedTo(sz); + ret = ret.expandedTo(sz); } if(d->rightWidget) { QSize sz = d->rightWidget->sizeHint(); diff --git a/src/widgets/widgets/qstackedwidget.cpp b/src/widgets/widgets/qstackedwidget.cpp index 2cec8a0b9c..19a2edf0f2 100644 --- a/src/widgets/widgets/qstackedwidget.cpp +++ b/src/widgets/widgets/qstackedwidget.cpp @@ -182,7 +182,9 @@ int QStackedWidget::insertWidget(int index, QWidget *widget) not deleted but simply removed from the stacked layout, causing it to be hidden. - \b{Note:} Ownership of \a widget reverts to the application. + \note Parent object and parent widget of \a widget will remain the + QStackedWidget. If the application wants to reuse the removed + \a widget, then it is recommended to re-parent it. \sa addWidget(), insertWidget(), currentWidget() */ diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp index 5a56c592a6..8473b261fc 100644 --- a/src/widgets/widgets/qtoolbutton.cpp +++ b/src/widgets/widgets/qtoolbutton.cpp @@ -897,7 +897,7 @@ void QToolButton::setDefaultAction(QAction *action) return; if (!actions().contains(action)) addAction(action); - setText(action->iconText()); + setText(action->text()); setIcon(action->icon()); #ifndef QT_NO_TOOLTIP setToolTip(action->toolTip()); diff --git a/src/winmain/qtmain_win.cpp b/src/winmain/qtmain_win.cpp index e88cecf0b3..2944e07e00 100644 --- a/src/winmain/qtmain_win.cpp +++ b/src/winmain/qtmain_win.cpp @@ -111,7 +111,7 @@ extern "C" int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR /*cmdParamarg*/, int argv[argc] = Q_NULLPTR; LocalFree(argvW); const int exitCode = main(argc, argv); - for (int i = 0; i < argc; ++i) + for (int i = 0; i < argc && argv[i]; ++i) delete [] argv[i]; delete [] argv; return exitCode; diff --git a/src/winmain/qtmain_winrt.cpp b/src/winmain/qtmain_winrt.cpp index 5a44df622a..e68da520e7 100644 --- a/src/winmain/qtmain_winrt.cpp +++ b/src/winmain/qtmain_winrt.cpp @@ -222,11 +222,49 @@ private: // Main entry point for Appx containers int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { +#if _MSC_VER < 1900 int argc = 0; char **argv, **env; _startupinfo info = { _query_new_mode() }; if (int init = __getmainargs(&argc, &argv, &env, false, &info)) return init; +#else + QByteArray commandLine = QString::fromWCharArray(GetCommandLine()).toUtf8(); + QVarLengthArray args; + args.append(commandLine.data()); + bool quote = false; + bool escape = false; + for (int i = 0; i < commandLine.size(); ++i) { + switch (commandLine.at(i)) { + case '\\': + escape = true; + break; + case '"': + if (escape) { + escape = false; + break; + } + quote = !quote; + commandLine[i] = '\0'; + break; + case ' ': + if (quote) + break; + commandLine[i] = '\0'; + if (args.last()[0] != '\0') + args.append(commandLine.data() + i + 1); + // fall through + default: + if (args.last()[0] == '\0') + args.last() = commandLine.data() + i; + escape = false; // only quotes are escaped + break; + } + } + int argc = args.size(); + char **argv = args.data(); + char **env = Q_NULLPTR; +#endif // _MSC_VER >= 1900 for (int i = 0; env && env[i]; ++i) { QByteArray var(env[i]); diff --git a/src/xml/doc/qtxml.qdocconf b/src/xml/doc/qtxml.qdocconf index 8ca421ff4e..419859ac8b 100644 --- a/src/xml/doc/qtxml.qdocconf +++ b/src/xml/doc/qtxml.qdocconf @@ -40,3 +40,6 @@ imagedirs += images \ navigation.landingpage = "Qt XML" navigation.cppclassespage = "Qt XML C++ Classes" + +# Add a thumbnail for examples that do not have images +manifestmeta.thumbnail.names = "QtXml/XML Stream Lint Example" diff --git a/tests/auto/corelib/global/qglobalstatic/qglobalstatic.pro b/tests/auto/corelib/global/qglobalstatic/qglobalstatic.pro index 21cab8f67d..7b374505ce 100644 --- a/tests/auto/corelib/global/qglobalstatic/qglobalstatic.pro +++ b/tests/auto/corelib/global/qglobalstatic/qglobalstatic.pro @@ -1,3 +1,4 @@ +CONFIG += testcase QT += testlib core-private QT -= gui diff --git a/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp b/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp index f792b34d48..3b730d97f9 100644 --- a/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp +++ b/tests/auto/corelib/io/qbuffer/tst_qbuffer.cpp @@ -151,7 +151,7 @@ void tst_QBuffer::readBlock() QCOMPARE(b.bytesAvailable(), (qint64) arraySize); b.open(QIODevice::WriteOnly); QCOMPARE(b.bytesAvailable(), (qint64) arraySize); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::read (QBuffer): WriteOnly device"); QCOMPARE(b.read(a, arraySize), (qint64) -1); // no read access b.close(); diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 98963108be..5025dd38db 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -2334,7 +2334,7 @@ void tst_QFile::readFromWriteOnlyFile() QFile file("writeonlyfile"); QVERIFY(file.open(QFile::WriteOnly)); char c; - QTest::ignoreMessage(QtWarningMsg, "QIODevice::read: WriteOnly device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::read (QFile, \"writeonlyfile\"): WriteOnly device"); QCOMPARE(file.read(&c, 1), qint64(-1)); } @@ -2343,7 +2343,7 @@ void tst_QFile::writeToReadOnlyFile() QFile file("readonlyfile"); QVERIFY(file.open(QFile::ReadOnly)); char c = 0; - QTest::ignoreMessage(QtWarningMsg, "QIODevice::write: ReadOnly device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::write (QFile, \"readonlyfile\"): ReadOnly device"); QCOMPARE(file.write(&c, 1), qint64(-1)); } diff --git a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp index f756588e80..565ca18899 100644 --- a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp +++ b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp @@ -224,7 +224,7 @@ void tst_QIODevice::unget() buf[0] = '@'; buf[1] = '@'; QTest::ignoreMessage(QtWarningMsg, - "QIODevice::readLine: Called with maxSize < 2"); + "QIODevice::readLine (QBuffer): Called with maxSize < 2"); QCOMPARE(buffer.readLine(buf, 1), qint64(-1)); QCOMPARE(buffer.readLine(buf, 2), qint64(i < 4 ? 1 : -1)); switch (i) { diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp index bef3d3a012..27614e0eb8 100644 --- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp +++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp @@ -57,11 +57,16 @@ private slots: void waitForLock(); void staleLockFromCrashedProcess_data(); void staleLockFromCrashedProcess(); + void staleLockFromCrashedProcessReusedPid(); void staleShortLockFromBusyProcess(); void staleLongLockFromBusyProcess(); void staleLockRace(); void noPermissions(); void noPermissionsWindows(); + void corruptedLockFile(); + +private: + static bool overwritePidInLockFile(const QString &filePath, qint64 pid); public: QString m_helperApp; @@ -276,6 +281,30 @@ void tst_QLockFile::staleLockFromCrashedProcess() #endif // !QT_NO_PROCESS } +void tst_QLockFile::staleLockFromCrashedProcessReusedPid() +{ +#if defined(QT_NO_PROCESS) + QSKIP("This test requires QProcess support"); +#elif defined(Q_OS_WINRT) || defined(Q_OS_WINCE) || defined(Q_OS_IOS) + QSKIP("We cannot retrieve information about other processes on this platform."); +#else + const QString fileName = dir.path() + "/staleLockFromCrashedProcessReusedPid"; + + int ret = QProcess::execute(m_helperApp, QStringList() << fileName << "-crash"); + QCOMPARE(ret, int(QLockFile::NoError)); + QVERIFY(QFile::exists(fileName)); + QVERIFY(overwritePidInLockFile(fileName, QCoreApplication::applicationPid())); + + QLockFile secondLock(fileName); + qint64 pid = 0; + secondLock.getLockInfo(&pid, 0, 0); + QCOMPARE(pid, QCoreApplication::applicationPid()); + secondLock.setStaleLockTime(0); + QVERIFY(secondLock.tryLock()); + QCOMPARE(int(secondLock.error()), int(QLockFile::NoError)); +#endif // !QT_NO_PROCESS +} + void tst_QLockFile::staleShortLockFromBusyProcess() { #ifdef QT_NO_PROCESS @@ -480,5 +509,41 @@ void tst_QLockFile::noPermissionsWindows() QCOMPARE(int(lockFile.error()), int(QLockFile::PermissionError)); } +void tst_QLockFile::corruptedLockFile() +{ + const QString fileName = dir.path() + "/corruptedLockFile"; + + { + // Create a empty file. Typically the result of a computer crash or hard disk full. + QFile file(fileName); + QVERIFY(file.open(QFile::WriteOnly)); + } + + QLockFile secondLock(fileName); + secondLock.setStaleLockTime(100); + QVERIFY(secondLock.tryLock(10000)); + QCOMPARE(int(secondLock.error()), int(QLockFile::NoError)); +} + +bool tst_QLockFile::overwritePidInLockFile(const QString &filePath, qint64 pid) +{ + QFile f(filePath); + if (!f.open(QFile::ReadWrite)) { + qWarning("Cannot open %s.", qPrintable(filePath)); + return false; + } + QByteArray buf = f.readAll(); + int i = buf.indexOf('\n'); + if (i < 0) { + qWarning("Unexpected lockfile content."); + return false; + } + buf.remove(0, i); + buf.prepend(QByteArray::number(pid)); + f.seek(0); + f.resize(buf.size()); + return f.write(buf) == buf.size(); +} + QTEST_MAIN(tst_QLockFile) #include "tst_qlockfile.moc" diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp index ff4963a960..924db17c04 100644 --- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp +++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp @@ -112,6 +112,22 @@ void tst_QCoreApplication::qAppName() // The application name should still be available after destruction; // global statics often rely on this. QCOMPARE(QCoreApplication::applicationName(), QString::fromLatin1(appName)); + + // Setting the appname before creating the application should work (QTBUG-45283) + const QString wantedAppName("my app name"); + { + int argc = 1; + char *argv[] = { const_cast(appName) }; + QCoreApplication::setApplicationName(wantedAppName); + TestApplication app(argc, argv); + QCOMPARE(::qAppName(), QString::fromLatin1(appName)); + QCOMPARE(QCoreApplication::applicationName(), wantedAppName); + } + QCOMPARE(QCoreApplication::applicationName(), wantedAppName); + + // Restore to initial value + QCoreApplication::setApplicationName(QString()); + QCOMPARE(QCoreApplication::applicationName(), QString()); } void tst_QCoreApplication::argc() diff --git a/tests/auto/corelib/kernel/qmetaenum/tst_qmetaenum.cpp b/tests/auto/corelib/kernel/qmetaenum/tst_qmetaenum.cpp index 17b00ebf63..5a10cf51e6 100644 --- a/tests/auto/corelib/kernel/qmetaenum/tst_qmetaenum.cpp +++ b/tests/auto/corelib/kernel/qmetaenum/tst_qmetaenum.cpp @@ -91,5 +91,13 @@ void tst_QMetaEnum::valuesToKeys() QCOMPARE(me.valueToKeys(windowFlags), expected); } +Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper::Value); +Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper::Value); +Q_STATIC_ASSERT(QtPrivate::IsQEnumHelper::Value); +Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper::Value); +Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper::Value); +Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper::Value); +Q_STATIC_ASSERT(!QtPrivate::IsQEnumHelper::Value); + QTEST_MAIN(tst_QMetaEnum) #include "tst_qmetaenum.moc" diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index b3333c6d68..9cdb1f47f8 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -142,8 +142,14 @@ public: class CustomGadget { Q_GADGET }; +class CustomGadget_NonDefaultConstructible { + Q_GADGET +public: + CustomGadget_NonDefaultConstructible(int) {}; +}; class CustomNonQObject {}; +class GadgetDerived : public CustomGadget {}; void tst_QMetaType::defined() { @@ -153,11 +159,12 @@ void tst_QMetaType::defined() QCOMPARE(int(QMetaTypeId2::Defined), 0); QCOMPARE(int(QMetaTypeId2::Defined), 1); QCOMPARE(int(QMetaTypeId2::Defined), 1); + QVERIFY(!QMetaTypeId2::Defined); QVERIFY(int(QMetaTypeId2::Defined)); QVERIFY(!QMetaTypeId2::Defined); QVERIFY(!QMetaTypeId2::Defined); QVERIFY(!QMetaTypeId2::Defined); - QVERIFY(!QMetaTypeId2::Defined); + QVERIFY(!QMetaTypeId2::Defined); } struct Bar diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 263cc5a07a..3ec84b5198 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -128,6 +128,7 @@ private slots: void connectWithReference(); void connectManyArguments(); void connectForwardDeclare(); + void connectNoDefaultConstructorArg(); void returnValue_data(); void returnValue(); void returnValue2_data(); @@ -5227,6 +5228,29 @@ void tst_QObject::connectForwardDeclare() QVERIFY(connect(&ob, &ForwardDeclareArguments::mySignal, &ob, &ForwardDeclareArguments::mySlot, Qt::QueuedConnection)); } +class NoDefaultConstructor +{ + Q_GADGET +public: + NoDefaultConstructor(int) {} +}; + +class NoDefaultContructorArguments : public QObject +{ + Q_OBJECT +signals: + void mySignal(const NoDefaultConstructor&); +public slots: + void mySlot(const NoDefaultConstructor&) {} +}; + +void tst_QObject::connectNoDefaultConstructorArg() +{ + NoDefaultContructorArguments ob; + // it should compile + QVERIFY(connect(&ob, &NoDefaultContructorArguments::mySignal, &ob, &NoDefaultContructorArguments::mySlot, Qt::QueuedConnection)); +} + class ReturnValue : public QObject { friend class tst_QObject; Q_OBJECT diff --git a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp index 96d0a62f6b..1292c3b98f 100644 --- a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp @@ -247,6 +247,9 @@ private slots: void qtbug_44963(); void qtbug_44783(); + void internalTransition(); + void conflictingTransition(); + void qtbug_46059(); }; class TestState : public QState @@ -256,10 +259,12 @@ public: Entry, Exit }; - TestState(QState *parent) - : QState(parent) {} - TestState(ChildMode mode) - : QState(mode) {} + TestState(QState *parent, const QString &objectName = QString()) + : QState(parent) + { setObjectName(objectName); } + TestState(ChildMode mode, const QString &objectName = QString()) + : QState(mode) + { setObjectName(objectName); } QList > events; protected: virtual void onEntry(QEvent *) { @@ -273,9 +278,9 @@ protected: class TestTransition : public QAbstractTransition { public: - TestTransition(QAbstractState *target) + TestTransition(QAbstractState *target, const QString &objectName = QString()) : QAbstractTransition() - { setTargetState(target); } + { setTargetState(target); setObjectName(objectName); } QList triggers; protected: virtual bool eventTest(QEvent *) { @@ -1352,15 +1357,16 @@ void tst_QStateMachine::stateEntryAndExit() { QStateMachine machine; - TestState *s1 = new TestState(&machine); - TestState *s11 = new TestState(s1); - TestState *s12 = new TestState(s1); - TestState *s2 = new TestState(&machine); + TestState *s1 = new TestState(&machine, "s1"); + TestState *s11 = new TestState(s1, "s11"); + TestState *s12 = new TestState(s1, "s12"); + TestState *s2 = new TestState(&machine, "s2"); QFinalState *s3 = new QFinalState(&machine); + s3->setObjectName("s3"); s1->setInitialState(s11); - TestTransition *t1 = new TestTransition(s12); + TestTransition *t1 = new TestTransition(s12, "t1"); s11->addTransition(t1); - TestTransition *t2 = new TestTransition(s2); + TestTransition *t2 = new TestTransition(s2, "t2"); s12->addTransition(t2); s2->addTransition(s3); @@ -6335,5 +6341,149 @@ void tst_QStateMachine::qtbug_44783() QVERIFY(machine.isRunning()); } +void tst_QStateMachine::internalTransition() +{ + SignalEmitter emitter; + + QStateMachine machine; + QState *s = new QState(&machine); + QState *s1 = new QState(s); + QState *s11 = new QState(s1); + + DEFINE_ACTIVE_SPY(s); + DEFINE_ACTIVE_SPY(s1); + DEFINE_ACTIVE_SPY(s11); + + machine.setInitialState(s); + s->setInitialState(s1); + s1->setInitialState(s11); + QSignalTransition *t = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s11); + t->setObjectName("s1->s11"); + t->setTransitionType(QAbstractTransition::InternalTransition); + + s->setObjectName("s"); + s1->setObjectName("s1"); + s11->setObjectName("s11"); + + machine.start(); + + QTRY_COMPARE(machine.configuration().contains(s), true); + QTRY_COMPARE(machine.configuration().contains(s1), true); + QTRY_COMPARE(machine.configuration().contains(s11), true); + TEST_ACTIVE_CHANGED(s, 1); + TEST_ACTIVE_CHANGED(s1, 1); + TEST_ACTIVE_CHANGED(s11, 1); + + emitter.emitSignalWithNoArg(); + + QTRY_COMPARE(machine.configuration().contains(s), true); + QTRY_COMPARE(machine.configuration().contains(s1), true); + QTRY_COMPARE(machine.configuration().contains(s11), true); + TEST_ACTIVE_CHANGED(s11, 3); + TEST_ACTIVE_CHANGED(s1, 1); // external transitions will return 3, internal transitions should return 1. + TEST_ACTIVE_CHANGED(s, 1); +} + +void tst_QStateMachine::conflictingTransition() +{ + SignalEmitter emitter; + + QStateMachine machine; + QState b(QState::ParallelStates, &machine); + QState c(&b); + QState d(QState::ParallelStates, &b); + QState e(&d); + QState e1(&e); + QState e2(&e); + QState f(&d); + QState f1(&f); + QState f2(&f); + QState a1(&machine); + + machine.setInitialState(&b); + e.setInitialState(&e1); + f.setInitialState(&f1); + c.addTransition(&emitter, SIGNAL(signalWithNoArg()), &a1)->setObjectName("c->a1"); + e1.addTransition(&emitter, SIGNAL(signalWithNoArg()), &e2)->setObjectName("e1->e2"); + f1.addTransition(&emitter, SIGNAL(signalWithNoArg()), &f2)->setObjectName("f1->f2"); + + b.setObjectName("b"); + c.setObjectName("c"); + d.setObjectName("d"); + e.setObjectName("e"); + e1.setObjectName("e1"); + e2.setObjectName("e2"); + f.setObjectName("f"); + f1.setObjectName("f1"); + f2.setObjectName("f2"); + a1.setObjectName("a1"); + + machine.start(); + + QTRY_COMPARE(machine.configuration().contains(&b), true); + QTRY_COMPARE(machine.configuration().contains(&c), true); + QTRY_COMPARE(machine.configuration().contains(&d), true); + QTRY_COMPARE(machine.configuration().contains(&e), true); + QTRY_COMPARE(machine.configuration().contains(&e1), true); + QTRY_COMPARE(machine.configuration().contains(&e2), false); + QTRY_COMPARE(machine.configuration().contains(&f), true); + QTRY_COMPARE(machine.configuration().contains(&f1), true); + QTRY_COMPARE(machine.configuration().contains(&f2), false); + QTRY_COMPARE(machine.configuration().contains(&a1), false); + + emitter.emitSignalWithNoArg(); + + QTRY_COMPARE(machine.configuration().contains(&b), true); + QTRY_COMPARE(machine.configuration().contains(&c), true); + QTRY_COMPARE(machine.configuration().contains(&d), true); + QTRY_COMPARE(machine.configuration().contains(&e), true); + QTRY_COMPARE(machine.configuration().contains(&e1), false); + QTRY_COMPARE(machine.configuration().contains(&e2), true); + QTRY_COMPARE(machine.configuration().contains(&f), true); + QTRY_COMPARE(machine.configuration().contains(&f1), false); + QTRY_COMPARE(machine.configuration().contains(&f2), true); + QTRY_COMPARE(machine.configuration().contains(&a1), false); + + QVERIFY(machine.isRunning()); +} + +void tst_QStateMachine::qtbug_46059() +{ + QStateMachine machine; + QState a(&machine); + QState b(&a); + QState c(&a); + QState success(&a); + QState failure(&machine); + + machine.setInitialState(&a); + a.setInitialState(&b); + b.addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), &c)); + c.addTransition(new EventTransition(QEvent::Type(QEvent::User + 2), &success)); + b.addTransition(new EventTransition(QEvent::Type(QEvent::User + 2), &failure)); + + machine.start(); + QCoreApplication::processEvents(); + + QTRY_COMPARE(machine.configuration().contains(&a), true); + QTRY_COMPARE(machine.configuration().contains(&b), true); + QTRY_COMPARE(machine.configuration().contains(&c), false); + QTRY_COMPARE(machine.configuration().contains(&failure), false); + QTRY_COMPARE(machine.configuration().contains(&success), false); + + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 0)), QStateMachine::HighPriority); + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1)), QStateMachine::HighPriority); + machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 2)), QStateMachine::NormalPriority); + QCoreApplication::processEvents(); + + QTRY_COMPARE(machine.configuration().contains(&a), true); + QTRY_COMPARE(machine.configuration().contains(&b), false); + QTRY_COMPARE(machine.configuration().contains(&c), false); + QTRY_COMPARE(machine.configuration().contains(&failure), false); + QTRY_COMPARE(machine.configuration().contains(&success), true); + + QVERIFY(machine.isRunning()); +} + QTEST_MAIN(tst_QStateMachine) #include "tst_qstatemachine.moc" diff --git a/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp b/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp index 01855a730e..76687bd478 100644 --- a/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp +++ b/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp @@ -43,6 +43,8 @@ class tst_QContiguousCache : public QObject { Q_OBJECT private slots: + void assignment(); + void empty(); void swap(); @@ -64,6 +66,16 @@ private slots: QTEST_MAIN(tst_QContiguousCache) +void tst_QContiguousCache::assignment() +{ + // compile-only test: QTBUG-45783 + QContiguousCache cc1, cc2; + // copy: + cc1 = cc2; + // move: + cc1 = qMove(cc2); +} + void tst_QContiguousCache::empty() { QContiguousCache c(10); diff --git a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp index 11c292db91..a07247316e 100644 --- a/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp @@ -39,10 +39,7 @@ #include #include - -#define QT_LINKED_LIBDBUS -#include -#include +#include static const char serviceName[] = "org.qtproject.autotests.qpong"; static const char objectPath[] = "/org/qtproject/qpong"; @@ -85,10 +82,8 @@ private slots: void sendCallErrors_data(); void sendCallErrors(); -#ifdef DBUS_TYPE_UNIX_FD void receiveUnknownType_data(); void receiveUnknownType(); -#endif void demarshallPrimitives_data(); void demarshallPrimitives(); @@ -1017,7 +1012,6 @@ void tst_QDBusMarshall::sendCallErrors() QCOMPARE(reply.errorMessage(), errorMsg); } -#ifdef DBUS_TYPE_UNIX_FD // If DBUS_TYPE_UNIX_FD is not defined, it means the current system's D-Bus library is too old for this test void tst_QDBusMarshall::receiveUnknownType_data() { @@ -1075,6 +1069,27 @@ public: } }; +// mostly the same as qdbusintegrator.cpp:connectionCapabilies +static bool canSendUnixFd(DBusConnection *connection) +{ + typedef dbus_bool_t (*can_send_type_t)(DBusConnection *, int); + static can_send_type_t can_send_type = 0; + +#if defined(QT_LINKED_LIBDBUS) +# if DBUS_VERSION-0 >= 0x010400 + can_send_type = dbus_connection_can_send_type; +# endif +#else + // run-time check if the next functions are available + can_send_type = (can_send_type_t)qdbus_resolve_conditionally("dbus_connection_can_send_type"); +#endif + +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +#endif + return can_send_type && can_send_type(connection, DBUS_TYPE_UNIX_FD); +} + void tst_QDBusMarshall::receiveUnknownType() { QDBusConnection con = QDBusConnection::sessionBus(); @@ -1088,7 +1103,8 @@ void tst_QDBusMarshall::receiveUnknownType() QVERIFY2(rawcon.data(), error.name); // check if this bus supports passing file descriptors - if (!q_dbus_connection_can_send_type(rawcon.data(), DBUS_TYPE_UNIX_FD)) + + if (!canSendUnixFd(rawcon.data())) QSKIP("Your session bus does not allow sending Unix file descriptors"); // make sure this QDBusConnection won't handle Unix file descriptors @@ -1184,7 +1200,6 @@ void tst_QDBusMarshall::receiveUnknownType() QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId); } } -#endif void tst_QDBusMarshall::demarshallPrimitives_data() { diff --git a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp index ced73dbf3b..63444b61ad 100644 --- a/tests/auto/dbus/qdbustype/tst_qdbustype.cpp +++ b/tests/auto/dbus/qdbustype/tst_qdbustype.cpp @@ -87,8 +87,19 @@ static void addFixedTypes() QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true; QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true; QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true; + #ifdef DBUS_TYPE_UNIX_FD_AS_STRING - QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true; +# ifndef QT_LINKED_LIBDBUS + // We have got the macro from dbus_minimal_p.h, so we need to check if + // the library recognizes this as valid type first. + // The following function was added for Unix FD support, so if it is + // present, so is support for Unix FDs. + bool supportsUnixFds = qdbus_resolve_conditionally("dbus_connection_can_send_type"); +# else + bool supportsUnixFds = true; +# endif + if (supportsUnixFds) + QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true; #endif } diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg new file mode 100644 index 0000000000..97deae3e25 Binary files /dev/null and b/tests/auto/gui/image/qimage/images/jpeg_exif_QTBUG-45865.jpg differ diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 2931185c8b..da29a57f98 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -184,6 +184,8 @@ private slots: void exifOrientation_data(); void exifOrientation(); + void exif_QTBUG45865(); + void cleanupFunctions(); void devicePixelRatio(); @@ -2816,31 +2818,56 @@ void tst_QImage::invertPixelsRGB() void tst_QImage::exifOrientation_data() { QTest::addColumn("fileName"); - QTest::newRow("Orientation 1, Intel format") << m_prefix + "jpeg_exif_orientation_value_1.jpg"; - QTest::newRow("Orientation 2, Intel format") << m_prefix + "jpeg_exif_orientation_value_2.jpg"; - QTest::newRow("Orientation 3, Intel format") << m_prefix + "jpeg_exif_orientation_value_3.jpg"; - QTest::newRow("Orientation 4, Intel format") << m_prefix + "jpeg_exif_orientation_value_4.jpg"; - QTest::newRow("Orientation 5, Intel format") << m_prefix + "jpeg_exif_orientation_value_5.jpg"; - QTest::newRow("Orientation 6, Intel format") << m_prefix + "jpeg_exif_orientation_value_6.jpg"; - QTest::newRow("Orientation 6, Motorola format") << m_prefix + "jpeg_exif_orientation_value_6_motorola.jpg"; - QTest::newRow("Orientation 7, Intel format") << m_prefix + "jpeg_exif_orientation_value_7.jpg"; - QTest::newRow("Orientation 8, Intel format") << m_prefix + "jpeg_exif_orientation_value_8.jpg"; + QTest::addColumn("orientation"); + QTest::newRow("Orientation 1, Intel format") << m_prefix + "jpeg_exif_orientation_value_1.jpg" << (int)QImageIOHandler::TransformationNone; + QTest::newRow("Orientation 2, Intel format") << m_prefix + "jpeg_exif_orientation_value_2.jpg" << (int)QImageIOHandler::TransformationMirror; + QTest::newRow("Orientation 3, Intel format") << m_prefix + "jpeg_exif_orientation_value_3.jpg" << (int)QImageIOHandler::TransformationRotate180; + QTest::newRow("Orientation 4, Intel format") << m_prefix + "jpeg_exif_orientation_value_4.jpg" << (int)QImageIOHandler::TransformationFlip; + QTest::newRow("Orientation 5, Intel format") << m_prefix + "jpeg_exif_orientation_value_5.jpg" << (int)QImageIOHandler::TransformationFlipAndRotate90; + QTest::newRow("Orientation 6, Intel format") << m_prefix + "jpeg_exif_orientation_value_6.jpg" << (int)QImageIOHandler::TransformationRotate90; + QTest::newRow("Orientation 6, Motorola format") << m_prefix + "jpeg_exif_orientation_value_6_motorola.jpg" << (int)QImageIOHandler::TransformationRotate90; + QTest::newRow("Orientation 7, Intel format") << m_prefix + "jpeg_exif_orientation_value_7.jpg" << (int)QImageIOHandler::TransformationMirrorAndRotate90; + QTest::newRow("Orientation 8, Intel format") << m_prefix + "jpeg_exif_orientation_value_8.jpg" << (int)QImageIOHandler::TransformationRotate270; } +QT_BEGIN_NAMESPACE +extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient); +QT_END_NAMESPACE +QT_USE_NAMESPACE + void tst_QImage::exifOrientation() { QFETCH(QString, fileName); + QFETCH(int, orientation); - QImage img; + QImageReader imageReader(fileName); + imageReader.setAutoTransform(true); + QCOMPARE(imageReader.transformation(), orientation); + QImage img = imageReader.read(); QRgb px; - - QVERIFY(img.load(fileName)); + QVERIFY(!img.isNull()); px = img.pixel(0, 0); QVERIFY(qRed(px) > 250 && qGreen(px) < 5 && qBlue(px) < 5); px = img.pixel(img.width() - 1, 0); QVERIFY(qRed(px) < 5 && qGreen(px) < 5 && qBlue(px) > 250); + + QImageReader imageReader2(fileName); + QCOMPARE(imageReader2.autoTransform(), false); + QCOMPARE(imageReader2.transformation(), orientation); + QImage img2 = imageReader2.read(); + qt_imageTransform(img2, imageReader2.transformation()); + QCOMPARE(img, img2); +} + +void tst_QImage::exif_QTBUG45865() +{ + QFile file(m_prefix + "jpeg_exif_QTBUG-45865.jpg"); + QVERIFY(file.open(QIODevice::ReadOnly)); + QByteArray byteArray = file.readAll(); + QImage image = QImage::fromData(byteArray); + QCOMPARE(image.size(), QSize(5, 8)); } static void cleanupFunction(void* info) diff --git a/tests/auto/gui/kernel/qtouchevent/BLACKLIST b/tests/auto/gui/kernel/qtouchevent/BLACKLIST new file mode 100644 index 0000000000..8e78d7e41f --- /dev/null +++ b/tests/auto/gui/kernel/qtouchevent/BLACKLIST @@ -0,0 +1,6 @@ +[basicRawEventTranslation] +linux +[multiPointRawEventTranslationOnTouchScreen] +linux +[multiPointRawEventTranslationOnTouchPad] +linux diff --git a/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro b/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro index 7136611165..b1e3c10724 100644 --- a/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro +++ b/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro @@ -1,3 +1,5 @@ +CONFIG += testcase +osx: CONFIG += insignificant_test # QTBUG-46266, crashes SOURCES=tst_qtouchevent.cpp TARGET=tst_qtouchevent QT += testlib widgets gui-private diff --git a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp index fe11f39242..aa1f573aa9 100644 --- a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp @@ -31,11 +31,16 @@ ** ****************************************************************************/ -#include -#include +#include +#include +#include +#include +#include +#include #include #include +// FIXME: Use static functions of QWindowSystemInterface introduced with HighDPI scaling in 5.6 instead. static QWindowSystemInterface::TouchPoint touchPoint(const QTouchEvent::TouchPoint& pt) { QWindowSystemInterface::TouchPoint p; @@ -72,8 +77,7 @@ public: ulong timestamp; QTouchDevice *deviceFromEvent; - tst_QTouchEventWidget() - : QWidget() + explicit tst_QTouchEventWidget(QWidget *parent = Q_NULLPTR) : QWidget(parent) { reset(); } @@ -88,7 +92,7 @@ public: deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } - bool event(QEvent *event) + bool event(QEvent *event) Q_DECL_OVERRIDE { switch (event->type()) { case QEvent::TouchBegin: @@ -142,8 +146,8 @@ public: bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; tst_QTouchEventGraphicsItem **weakpointer; - tst_QTouchEventGraphicsItem() - : QGraphicsItem(), weakpointer(0) + explicit tst_QTouchEventGraphicsItem(QGraphicsItem *parent = Q_NULLPTR) + : QGraphicsItem(parent), weakpointer(0) { reset(); } @@ -165,10 +169,10 @@ public: deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } - QRectF boundingRect() const { return QRectF(0, 0, 10, 10); } - void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) { } + QRectF boundingRect() const Q_DECL_OVERRIDE { return QRectF(0, 0, 10, 10); } + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) Q_DECL_OVERRIDE { } - bool sceneEvent(QEvent *event) + bool sceneEvent(QEvent *event) Q_DECL_OVERRIDE { switch (event->type()) { case QEvent::TouchBegin: @@ -214,9 +218,9 @@ class tst_QTouchEvent : public QObject Q_OBJECT public: tst_QTouchEvent(); - ~tst_QTouchEvent() { } private slots: + void cleanup(); void touchDisabledByDefault(); void touchEventAcceptedByDefault(); void touchBeginPropagatesWhenIgnored(); @@ -236,15 +240,18 @@ private: QTouchDevice *touchPadDevice; }; -tst_QTouchEvent::tst_QTouchEvent() +tst_QTouchEvent::tst_QTouchEvent() : touchScreenDevice(new QTouchDevice), touchPadDevice(new QTouchDevice) { - touchScreenDevice = new QTouchDevice; - touchPadDevice = new QTouchDevice; touchPadDevice->setType(QTouchDevice::TouchPad); QWindowSystemInterface::registerTouchDevice(touchScreenDevice); QWindowSystemInterface::registerTouchDevice(touchPadDevice); } +void tst_QTouchEvent::cleanup() +{ + QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); +} + void tst_QTouchEvent::touchDisabledByDefault() { // QWidget @@ -261,8 +268,7 @@ void tst_QTouchEvent::touchDisabledByDefault() Qt::NoModifier, Qt::TouchPointPressed, touchPoints); - bool res = QApplication::sendEvent(&widget, &touchEvent); - QVERIFY(!res); + QVERIFY(!QApplication::sendEvent(&widget, &touchEvent)); QVERIFY(!touchEvent.isAccepted()); } @@ -290,8 +296,7 @@ void tst_QTouchEvent::touchDisabledByDefault() Qt::NoModifier, Qt::TouchPointPressed, (QList() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(!res); + QVERIFY(!QApplication::sendEvent(view.viewport(), &touchEvent)); QVERIFY(!touchEvent.isAccepted()); QVERIFY(!item.seenTouchBegin); } @@ -299,7 +304,7 @@ void tst_QTouchEvent::touchDisabledByDefault() void tst_QTouchEvent::touchEventAcceptedByDefault() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); // QWidget @@ -317,16 +322,14 @@ void tst_QTouchEvent::touchEventAcceptedByDefault() Qt::NoModifier, Qt::TouchPointPressed, touchPoints); - bool res = QApplication::sendEvent(&widget, &touchEvent); - QVERIFY(res); - QVERIFY(touchEvent.isAccepted()); + QVERIFY(QApplication::sendEvent(&widget, &touchEvent)); + QVERIFY(!touchEvent.isAccepted()); // Qt 5.X ignores touch events. // tst_QTouchEventWidget does handle, sending succeeds tst_QTouchEventWidget touchWidget; touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchEvent.ignore(); - res = QApplication::sendEvent(&touchWidget, &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&touchWidget, &touchEvent)); QVERIFY(touchEvent.isAccepted()); } @@ -355,8 +358,7 @@ void tst_QTouchEvent::touchEventAcceptedByDefault() Qt::NoModifier, Qt::TouchPointPressed, (QList() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(item.seenTouchBegin); } @@ -383,8 +385,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() Qt::NoModifier, Qt::TouchPointPressed, touchPoints); - bool res = QApplication::sendEvent(&grandchild, &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&grandchild, &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(grandchild.seenTouchBegin); QVERIFY(child.seenTouchBegin); @@ -398,8 +399,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() grandchild.setAttribute(Qt::WA_AcceptTouchEvents, false); touchEvent.ignore(); - res = QApplication::sendEvent(&grandchild, &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&grandchild, &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(!grandchild.seenTouchBegin); QVERIFY(child.seenTouchBegin); @@ -435,8 +435,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() Qt::NoModifier, Qt::TouchPointPressed, (QList() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(grandchild.seenTouchBegin); QVERIFY(child.seenTouchBegin); @@ -471,8 +470,7 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() Qt::NoModifier, Qt::TouchPointPressed, (QList() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEvent)); QVERIFY(touchEvent.isAccepted()); QVERIFY(!grandchild.seenTouchBegin); QVERIFY(child.seenTouchBegin); @@ -499,8 +497,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointPressed, touchPoints); - bool res = QApplication::sendEvent(&child, &touchBeginEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&child, &touchBeginEvent)); QVERIFY(touchBeginEvent.isAccepted()); QVERIFY(child.seenTouchBegin); QVERIFY(!window.seenTouchBegin); @@ -511,8 +508,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointMoved, touchPoints); - res = QApplication::sendEvent(&child, &touchUpdateEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&child, &touchUpdateEvent)); QVERIFY(!touchUpdateEvent.isAccepted()); QVERIFY(child.seenTouchUpdate); QVERIFY(!window.seenTouchUpdate); @@ -523,8 +519,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - res = QApplication::sendEvent(&child, &touchEndEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(&child, &touchEndEvent)); QVERIFY(!touchEndEvent.isAccepted()); QVERIFY(child.seenTouchEnd); QVERIFY(!window.seenTouchEnd); @@ -558,8 +553,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointPressed, (QList() << touchPoint)); - bool res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent)); QVERIFY(touchBeginEvent.isAccepted()); QVERIFY(child.seenTouchBegin); QVERIFY(!root.seenTouchBegin); @@ -571,8 +565,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointMoved, (QList() << touchPoint)); - res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent)); // the scene accepts the event, since it found an item to send the event to QVERIFY(!touchUpdateEvent.isAccepted()); QVERIFY(child.seenTouchUpdate); @@ -585,8 +578,7 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() Qt::NoModifier, Qt::TouchPointReleased, (QList() << touchPoint)); - res = QApplication::sendEvent(view.viewport(), &touchEndEvent); - QVERIFY(res); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent)); // the scene accepts the event, since it found an item to send the event to QVERIFY(!touchEndEvent.isAccepted()); QVERIFY(child.seenTouchEnd); @@ -601,17 +593,20 @@ QPointF normalized(const QPointF &pos, const QRectF &rect) void tst_QTouchEvent::basicRawEventTranslation() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchWidget.setGeometry(100, 100, 400, 300); + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowActive(&touchWidget)); QPointF pos = touchWidget.rect().center(); QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint()); QPointF delta(10, 10); - QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); QTouchEvent::TouchPoint rawTouchPoint; rawTouchPoint.setId(0); @@ -726,24 +721,24 @@ void tst_QTouchEvent::basicRawEventTranslation() void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchWidget.setGeometry(100, 100, 400, 300); - tst_QTouchEventWidget leftWidget; - leftWidget.setParent(&touchWidget); + tst_QTouchEventWidget leftWidget(&touchWidget); leftWidget.setAttribute(Qt::WA_AcceptTouchEvents); leftWidget.setGeometry(0, 100, 100, 100); - leftWidget.show(); - tst_QTouchEventWidget rightWidget; - rightWidget.setParent(&touchWidget); + tst_QTouchEventWidget rightWidget(&touchWidget); rightWidget.setAttribute(Qt::WA_AcceptTouchEvents); rightWidget.setGeometry(300, 100, 100, 100); - rightWidget.show(); + + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowActive(&touchWidget)); QPointF leftPos = leftWidget.rect().center(); QPointF rightPos = rightWidget.rect().center(); @@ -751,8 +746,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint()); QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint()); QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint()); - QPointF delta(10, 10); - QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); QList rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); @@ -956,24 +950,25 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchWidget.setGeometry(100, 100, 400, 300); - tst_QTouchEventWidget leftWidget; - leftWidget.setParent(&touchWidget); + tst_QTouchEventWidget leftWidget(&touchWidget); leftWidget.setAttribute(Qt::WA_AcceptTouchEvents); leftWidget.setGeometry(0, 100, 100, 100); - leftWidget.show(); + leftWidget.acceptTouchBegin =true; - tst_QTouchEventWidget rightWidget; - rightWidget.setParent(&touchWidget); + tst_QTouchEventWidget rightWidget(&touchWidget); rightWidget.setAttribute(Qt::WA_AcceptTouchEvents); rightWidget.setGeometry(300, 100, 100, 100); - rightWidget.show(); + + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowActive(&touchWidget)); QPointF leftPos = leftWidget.rect().center(); QPointF rightPos = rightWidget.rect().center(); @@ -981,8 +976,7 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint()); QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint()); QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint()); - QPointF delta(10, 10); - QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); QList rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); @@ -1003,7 +997,8 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() QVERIFY(!touchWidget.seenTouchBegin); QVERIFY(!touchWidget.seenTouchUpdate); QVERIFY(!touchWidget.seenTouchEnd); - QVERIFY(leftWidget.seenTouchBegin); + QEXPECT_FAIL("", "QTBUG-46266, fails in Qt 5", Abort); + QVERIFY(!leftWidget.seenTouchBegin); QVERIFY(!leftWidget.seenTouchUpdate); QVERIFY(!leftWidget.seenTouchEnd); QVERIFY(!rightWidget.seenTouchBegin); @@ -1186,19 +1181,15 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() void tst_QTouchEvent::deleteInEventHandler() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); // QWidget { QWidget window; - tst_QTouchEventWidget *child1, *child2, *child3; - child1 = new tst_QTouchEventWidget; - child2 = new tst_QTouchEventWidget; - child3 = new tst_QTouchEventWidget; - child1->setParent(&window); - child2->setParent(&window); - child3->setParent(&window); + QPointer child1 = new tst_QTouchEventWidget(&window); + QPointer child2 = new tst_QTouchEventWidget(&window); + QPointer child3 = new tst_QTouchEventWidget(&window); child1->setAttribute(Qt::WA_AcceptTouchEvents); child2->setAttribute(Qt::WA_AcceptTouchEvents); child3->setAttribute(Qt::WA_AcceptTouchEvents); @@ -1223,47 +1214,43 @@ void tst_QTouchEvent::deleteInEventHandler() Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - QPointer p; - bool res; - touchBeginEvent.ignore(); - p = child1; - res = QApplication::sendEvent(child1, &touchBeginEvent); + QVERIFY(QApplication::sendEvent(child1, &touchBeginEvent)); // event is handled, but widget should be deleted - QVERIFY(res && touchBeginEvent.isAccepted() && p.isNull()); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(child1.isNull()); touchBeginEvent.ignore(); - p = child2; - res = QApplication::sendEvent(child2, &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + QVERIFY(QApplication::sendEvent(child2, &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(!child2.isNull()); touchUpdateEvent.ignore(); - res = QApplication::sendEvent(child2, &touchUpdateEvent); - QVERIFY(res && touchUpdateEvent.isAccepted() && p.isNull()); + QVERIFY(QApplication::sendEvent(child2, &touchUpdateEvent)); + QVERIFY(touchUpdateEvent.isAccepted()); + QVERIFY(child2.isNull()); touchBeginEvent.ignore(); - p = child3; - res = QApplication::sendEvent(child3, &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + QVERIFY(QApplication::sendEvent(child3, &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(!child3.isNull()); touchUpdateEvent.ignore(); - res = QApplication::sendEvent(child3, &touchUpdateEvent); - QVERIFY(res && touchUpdateEvent.isAccepted() && !p.isNull()); + QVERIFY(QApplication::sendEvent(child3, &touchUpdateEvent)); + QVERIFY(touchUpdateEvent.isAccepted()); + QVERIFY(!child3.isNull()); touchEndEvent.ignore(); - res = QApplication::sendEvent(child3, &touchEndEvent); - QVERIFY(res && touchEndEvent.isAccepted() && p.isNull()); + QVERIFY(QApplication::sendEvent(child3, &touchEndEvent)); + QVERIFY(touchEndEvent.isAccepted()); + QVERIFY(child3.isNull()); } // QGraphicsView { QGraphicsScene scene; QGraphicsView view(&scene); - tst_QTouchEventGraphicsItem *root, *child1, *child2, *child3; - root = new tst_QTouchEventGraphicsItem; - child1 = new tst_QTouchEventGraphicsItem; - child2 = new tst_QTouchEventGraphicsItem; - child3 = new tst_QTouchEventGraphicsItem; - child1->setParentItem(root); - child2->setParentItem(root); - child3->setParentItem(root); + QScopedPointer root(new tst_QTouchEventGraphicsItem); + tst_QTouchEventGraphicsItem *child1 = new tst_QTouchEventGraphicsItem(root.data()); + tst_QTouchEventGraphicsItem *child2 = new tst_QTouchEventGraphicsItem(root.data()); + tst_QTouchEventGraphicsItem *child3 = new tst_QTouchEventGraphicsItem(root.data()); child1->setZValue(1.); child2->setZValue(0.); child3->setZValue(-1.); @@ -1274,7 +1261,7 @@ void tst_QTouchEvent::deleteInEventHandler() child2->deleteInTouchUpdate = true; child3->deleteInTouchEnd = true; - scene.addItem(root); + scene.addItem(root.data()); view.resize(200, 200); view.fitInView(scene.sceneRect()); @@ -1302,71 +1289,75 @@ void tst_QTouchEvent::deleteInEventHandler() Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - bool res; child1->weakpointer = &child1; touchBeginEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && !child1); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(!child1); touchUpdateEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); - QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); // Qt 5.X ignores touch events. + QVERIFY(!child1); touchEndEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchEndEvent); - QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(!child1); child2->weakpointer = &child2; touchBeginEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && child2); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(child2); touchUpdateEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); - QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(!child2); touchEndEvent.ignore(); - res = QApplication::sendEvent(view.viewport(), &touchEndEvent); - QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(!child2); child3->weakpointer = &child3; - res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); - QVERIFY(res && touchBeginEvent.isAccepted() && child3); - res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); - QVERIFY(res && !touchUpdateEvent.isAccepted() && child3); - res = QApplication::sendEvent(view.viewport(), &touchEndEvent); - QVERIFY(res && !touchEndEvent.isAccepted() && !child3); - - delete root; + QVERIFY(QApplication::sendEvent(view.viewport(), &touchBeginEvent)); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(child3); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchUpdateEvent)); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(child3); + QVERIFY(QApplication::sendEvent(view.viewport(), &touchEndEvent)); + QVERIFY(!touchEndEvent.isAccepted()); + QVERIFY(!child3); } } void tst_QTouchEvent::deleteInRawEventTranslation() { - if (qApp->platformName().toLower() == QLatin1String("wayland")) + if (!QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive)) QSKIP("Wayland: This fails. Figure out why."); tst_QTouchEventWidget touchWidget; + touchWidget.setWindowTitle(QTest::currentTestFunction()); touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); touchWidget.setGeometry(100, 100, 300, 300); - tst_QTouchEventWidget *leftWidget = new tst_QTouchEventWidget; - leftWidget->setParent(&touchWidget); + QPointer leftWidget = new tst_QTouchEventWidget(&touchWidget); leftWidget->setAttribute(Qt::WA_AcceptTouchEvents); leftWidget->setGeometry(0, 100, 100, 100); leftWidget->deleteInTouchBegin = true; - leftWidget->show(); - tst_QTouchEventWidget *centerWidget = new tst_QTouchEventWidget; - centerWidget->setParent(&touchWidget); + QPointer centerWidget = new tst_QTouchEventWidget(&touchWidget); centerWidget->setAttribute(Qt::WA_AcceptTouchEvents); centerWidget->setGeometry(100, 100, 100, 100); centerWidget->deleteInTouchUpdate = true; - centerWidget->show(); - tst_QTouchEventWidget *rightWidget = new tst_QTouchEventWidget; - rightWidget->setParent(&touchWidget); + QPointer rightWidget = new tst_QTouchEventWidget(&touchWidget); rightWidget->setAttribute(Qt::WA_AcceptTouchEvents); rightWidget->setGeometry(200, 100, 100, 100); rightWidget->deleteInTouchEnd = true; - rightWidget->show(); + + touchWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&touchWidget)); QPointF leftPos = leftWidget->rect().center(); QPointF centerPos = centerWidget->rect().center(); @@ -1374,9 +1365,7 @@ void tst_QTouchEvent::deleteInRawEventTranslation() QPointF leftScreenPos = leftWidget->mapToGlobal(leftPos.toPoint()); QPointF centerScreenPos = centerWidget->mapToGlobal(centerPos.toPoint()); QPointF rightScreenPos = rightWidget->mapToGlobal(rightPos.toPoint()); - QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); - - QPointer pl = leftWidget, pc = centerWidget, pr = rightWidget; + QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget); QList rawTouchPoints; rawTouchPoints.append(QTouchEvent::TouchPoint(0)); @@ -1398,7 +1387,9 @@ void tst_QTouchEvent::deleteInRawEventTranslation() touchScreenDevice, touchPointList(rawTouchPoints)); QCoreApplication::processEvents(); - QVERIFY(pl.isNull() && !pc.isNull() && !pr.isNull()); + QVERIFY(leftWidget.isNull()); + QVERIFY(!centerWidget.isNull()); + QVERIFY(!rightWidget.isNull()); // generate update events on all widget, the center widget should die rawTouchPoints[0].setState(Qt::TouchPointMoved); @@ -1455,14 +1446,13 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget() { QGraphicsScene scene; QGraphicsView view(&scene); - tst_QTouchEventGraphicsItem *root; - root = new tst_QTouchEventGraphicsItem; + QScopedPointer root(new tst_QTouchEventGraphicsItem); root->setAcceptTouchEvents(true); - scene.addItem(root); + scene.addItem(root.data()); - QGraphicsWidget *glassWidget = new QGraphicsWidget; + QScopedPointer glassWidget(new QGraphicsWidget); glassWidget->setMinimumSize(100, 100); - scene.addItem(glassWidget); + scene.addItem(glassWidget.data()); view.resize(200, 200); view.show(); @@ -1478,7 +1468,7 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget() .release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()) .release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); - QCOMPARE(root->touchBeginCounter, 1); + QTRY_COMPARE(root->touchBeginCounter, 1); QCOMPARE(root->touchUpdateCounter, 1); QCOMPARE(root->touchEndCounter, 1); QCOMPARE(root->touchUpdatePoints.size(), 2); @@ -1498,17 +1488,13 @@ void tst_QTouchEvent::touchBeginWithGraphicsWidget() QCOMPARE(root->touchBeginCounter, 0); QCOMPARE(root->touchUpdateCounter, 0); QCOMPARE(root->touchEndCounter, 0); - - - delete root; - delete glassWidget; } class WindowTouchEventFilter : public QObject { Q_OBJECT public: - bool eventFilter(QObject *obj, QEvent *event); + bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; struct TouchInfo { QList points; QEvent::Type lastSeenType; @@ -1537,18 +1523,18 @@ void tst_QTouchEvent::testQGuiAppDelivery() device->setType(QTouchDevice::TouchScreen); QWindowSystemInterface::registerTouchDevice(device); - QWindow *w = new QWindow; - w->setGeometry(100, 100, 100, 100); - w->show(); - QVERIFY(QTest::qWaitForWindowExposed(w)); + QWindow w; + w.setGeometry(100, 100, 100, 100); + w.show(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); WindowTouchEventFilter filter; - w->installEventFilter(&filter); + w.installEventFilter(&filter); QList points; // Pass empty list, should be ignored. - QWindowSystemInterface::handleTouchEvent(w, 0, points); + QWindowSystemInterface::handleTouchEvent(&w, 0, points); QCoreApplication::processEvents(); QCOMPARE(filter.d.isEmpty(), true); @@ -1559,12 +1545,12 @@ void tst_QTouchEvent::testQGuiAppDelivery() points.append(tp); // Pass 0 as device, should be ignored. - QWindowSystemInterface::handleTouchEvent(w, 0, points); + QWindowSystemInterface::handleTouchEvent(&w, 0, points); QCoreApplication::processEvents(); QCOMPARE(filter.d.isEmpty(), true); // Now the real thing. - QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchBegin + QWindowSystemInterface::handleTouchEvent(&w, device, points); // TouchBegin QCoreApplication::processEvents(); QCOMPARE(filter.d.count(), 1); QCOMPARE(filter.d.contains(device), true); @@ -1572,7 +1558,7 @@ void tst_QTouchEvent::testQGuiAppDelivery() QCOMPARE(filter.d.value(device).lastSeenType, QEvent::TouchBegin); points[0].state = Qt::TouchPointMoved; - QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchUpdate + QWindowSystemInterface::handleTouchEvent(&w, device, points); // TouchUpdate QCoreApplication::processEvents(); QCOMPARE(filter.d.count(), 1); QCOMPARE(filter.d.contains(device), true); @@ -1580,7 +1566,7 @@ void tst_QTouchEvent::testQGuiAppDelivery() QCOMPARE(filter.d.value(device).lastSeenType, QEvent::TouchUpdate); points[0].state = Qt::TouchPointReleased; - QWindowSystemInterface::handleTouchEvent(w, device, points); // TouchEnd + QWindowSystemInterface::handleTouchEvent(&w, device, points); // TouchEnd QCoreApplication::processEvents(); QCOMPARE(filter.d.count(), 1); QCOMPARE(filter.d.contains(device), true); @@ -1597,13 +1583,13 @@ void tst_QTouchEvent::testMultiDevice() deviceTwo->setType(QTouchDevice::TouchScreen); QWindowSystemInterface::registerTouchDevice(deviceTwo); - QWindow *w = new QWindow; - w->setGeometry(100, 100, 100, 100); - w->show(); - QVERIFY(QTest::qWaitForWindowExposed(w)); + QWindow w; + w.setGeometry(100, 100, 100, 100); + w.show(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); WindowTouchEventFilter filter; - w->installEventFilter(&filter); + w.installEventFilter(&filter); QList pointsOne, pointsTwo; @@ -1620,8 +1606,8 @@ void tst_QTouchEvent::testMultiDevice() tp.area = QRectF(140, 140, 20, 20); pointsTwo.append(tp); - QWindowSystemInterface::handleTouchEvent(w, deviceOne, pointsOne); - QWindowSystemInterface::handleTouchEvent(w, deviceTwo, pointsTwo); + QWindowSystemInterface::handleTouchEvent(&w, deviceOne, pointsOne); + QWindowSystemInterface::handleTouchEvent(&w, deviceTwo, pointsTwo); QCoreApplication::processEvents(); QCOMPARE(filter.d.contains(deviceOne), true); diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST new file mode 100644 index 0000000000..ee9709e68b --- /dev/null +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -0,0 +1,6 @@ +[positioning:default] +ubuntu-14.04 +[modalWindowPosition] +ubuntu-14.04 +[modalWithChildWindow] +ubuntu-14.04 diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 517f7fe3bd..666bedc8c2 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -470,6 +470,9 @@ private Q_SLOTS: void ioHttpChangeMaxRedirects(); void ioHttpRedirectErrors_data(); void ioHttpRedirectErrors(); +#ifndef QT_NO_SSL + void putWithServerClosingConnectionImmediately(); +#endif // NOTE: This test must be last! void parentingRepliesToTheApp(); @@ -4744,18 +4747,22 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag() class SslServer : public QTcpServer { Q_OBJECT public: - SslServer() : socket(0) {}; + SslServer() : socket(0), m_ssl(true) {} void incomingConnection(qintptr socketDescriptor) { QSslSocket *serverSocket = new QSslSocket; serverSocket->setParent(this); if (serverSocket->setSocketDescriptor(socketDescriptor)) { + connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + if (!m_ssl) { + emit newPlainConnection(serverSocket); + return; + } QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath(); if (testDataDir.isEmpty()) testDataDir = QCoreApplication::applicationDirPath(); connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot())); - connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); serverSocket->setProtocol(QSsl::AnyProtocol); connect(serverSocket, SIGNAL(sslErrors(QList)), serverSocket, SLOT(ignoreSslErrors())); serverSocket->setLocalCertificate(testDataDir + "/certs/server.pem"); @@ -4766,11 +4773,12 @@ public: } } signals: - void newEncryptedConnection(); + void newEncryptedConnection(QSslSocket *s); + void newPlainConnection(QSslSocket *s); public slots: void encryptedSlot() { socket = (QSslSocket*) sender(); - emit newEncryptedConnection(); + emit newEncryptedConnection(socket); } void readyReadSlot() { // for the incoming sockets, not the server socket @@ -4779,6 +4787,7 @@ public slots: public: QSslSocket *socket; + bool m_ssl; }; // very similar to ioPostToHttpUploadProgress but for SSL @@ -4806,7 +4815,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() QNetworkReplyPtr reply(manager.post(request, sourceFile)); QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64))); - connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop())); connect(reply, SIGNAL(sslErrors(QList)), reply.data(), SLOT(ignoreSslErrors())); // get the request started and the incoming socket connected @@ -4814,7 +4823,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() QVERIFY(!QTestEventLoop::instance().timeout()); QTcpSocket *incomingSocket = server.socket; QVERIFY(incomingSocket); - disconnect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + disconnect(&server, SIGNAL(newEncryptedConnection(QSslSocket*)), &QTestEventLoop::instance(), SLOT(exitLoop())); incomingSocket->setReadBufferSize(1*1024); @@ -8147,6 +8156,159 @@ void tst_QNetworkReply::ioHttpRedirectErrors() QCOMPARE(spy.count(), 1); QVERIFY(reply->error() == error); } +#ifndef QT_NO_SSL + +class PutWithServerClosingConnectionImmediatelyHandler: public QObject +{ + Q_OBJECT +public: + bool m_parsedHeaders; + QByteArray m_receivedData; + QByteArray m_expectedData; + QSslSocket *m_socket; + PutWithServerClosingConnectionImmediatelyHandler(QSslSocket *s, QByteArray expected) :m_parsedHeaders(false), m_expectedData(expected), m_socket(s) + { + m_socket->setParent(this); + connect(m_socket, SIGNAL(readyRead()), SLOT(readyReadSlot())); + connect(m_socket, SIGNAL(disconnected()), SLOT(disconnectedSlot())); + } +signals: + void correctFileUploadReceived(); + void corruptFileUploadReceived(); + +public slots: + void closeDelayed() { + m_socket->close(); + } + + void readyReadSlot() + { + QByteArray data = m_socket->readAll(); + m_receivedData += data; + if (!m_parsedHeaders && m_receivedData.contains("\r\n\r\n")) { + m_parsedHeaders = true; + QTimer::singleShot(qrand()%10, this, SLOT(closeDelayed())); // simulate random network latency + // This server simulates a web server connection closing, e.g. because of Apaches MaxKeepAliveRequests or KeepAliveTimeout + // In this case QNAM needs to re-send the upload data but it had a bug which then corrupts the upload + // This test catches that. + } + + } + void disconnectedSlot() + { + if (m_parsedHeaders) { + //qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n")); + m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data + } + if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) { + // We had received some data but it is corrupt! + qDebug() << "CORRUPT" << m_receivedData.count(); + + // Use this to track down the pattern of the corruption and conclude the source +// QFile a("/tmp/corrupt"); +// a.open(QIODevice::WriteOnly); +// a.write(m_receivedData); +// a.close(); + +// QFile b("/tmp/correct"); +// b.open(QIODevice::WriteOnly); +// b.write(m_expectedData); +// b.close(); + //exit(1); + emit corruptFileUploadReceived(); + } else { + emit correctFileUploadReceived(); + } + } +}; + +class PutWithServerClosingConnectionImmediatelyServer: public SslServer +{ + Q_OBJECT +public: + int m_correctUploads; + int m_corruptUploads; + int m_repliesFinished; + int m_expectedReplies; + QByteArray m_expectedData; + PutWithServerClosingConnectionImmediatelyServer() : SslServer(), m_correctUploads(0), m_corruptUploads(0), m_repliesFinished(0), m_expectedReplies(0) + { + QObject::connect(this, SIGNAL(newEncryptedConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*))); + QObject::connect(this, SIGNAL(newPlainConnection(QSslSocket*)), this, SLOT(createHandlerForConnection(QSslSocket*))); + } + +public slots: + void createHandlerForConnection(QSslSocket* s) { + PutWithServerClosingConnectionImmediatelyHandler *handler = new PutWithServerClosingConnectionImmediatelyHandler(s, m_expectedData); + handler->setParent(this); + QObject::connect(handler, SIGNAL(correctFileUploadReceived()), this, SLOT(increaseCorrect())); + QObject::connect(handler, SIGNAL(corruptFileUploadReceived()), this, SLOT(increaseCorrupt())); + } + void increaseCorrect() { + m_correctUploads++; + } + void increaseCorrupt() { + m_corruptUploads++; + } + void replyFinished() { + m_repliesFinished++; + if (m_repliesFinished == m_expectedReplies) { + QTestEventLoop::instance().exitLoop(); + } + } +}; + + + +void tst_QNetworkReply::putWithServerClosingConnectionImmediately() +{ + const int numUploads = 40; + qint64 wantedSize = 512*1024; // 512 kB + QByteArray sourceFile; + for (int i = 0; i < wantedSize; ++i) { + sourceFile += (char)'a' +(i%26); + } + bool withSsl = false; + + for (int s = 0; s <= 1; s++) { + withSsl = (s == 1); + // Test also needs to run several times because of 9c2ecf89 + for (int j = 0; j < 20; j++) { + // emulate a minimal https server + PutWithServerClosingConnectionImmediatelyServer server; + server.m_ssl = withSsl; + server.m_expectedData = sourceFile; + server.m_expectedReplies = numUploads; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + for (int i = 0; i < numUploads; i++) { + // create the request + QUrl url = QUrl(QString("http%1://127.0.0.1:%2/file=%3").arg(withSsl ? "s" : "").arg(server.serverPort()).arg(i)); + QNetworkRequest request(url); + QNetworkReply *reply = manager.put(request, sourceFile); + connect(reply, SIGNAL(sslErrors(QList)), reply, SLOT(ignoreSslErrors())); + connect(reply, SIGNAL(finished()), &server, SLOT(replyFinished())); + reply->setParent(&server); + } + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + + //qDebug() << "correct=" << server.m_correctUploads << "corrupt=" << server.m_corruptUploads << "expected=" < 5); + // Because actually important is that we don't get any corruption: + QCOMPARE(server.m_corruptUploads, 0); + + server.close(); + } + } + + +} + +#endif // NOTE: This test must be last testcase in tst_qnetworkreply! void tst_QNetworkReply::parentingRepliesToTheApp() diff --git a/tests/auto/network/kernel/qhostinfo/BLACKLIST b/tests/auto/network/kernel/qhostinfo/BLACKLIST deleted file mode 100644 index ea4b64d7c2..0000000000 --- a/tests/auto/network/kernel/qhostinfo/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -# QTBUG-23837 -[abortHostLookupInDifferentThread] -opensuse-13.1 64bit diff --git a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp index 9762e8244c..599e475beb 100644 --- a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp @@ -126,7 +126,6 @@ private slots: void cache(); void abortHostLookup(); - void abortHostLookupInDifferentThread(); protected slots: void resultsReady(const QHostInfo &); @@ -621,25 +620,5 @@ public: int id; }; -void tst_QHostInfo::abortHostLookupInDifferentThread() -{ - //reset counter - lookupsDoneCounter = 0; - bool valid = false; - int id = -1; - QHostInfo result = qt_qhostinfo_lookup("a-single" TEST_DOMAIN, this, SLOT(resultsReady(QHostInfo)), &valid, &id); - QVERIFY(!valid); - QThread thread; - LookupAborter aborter; - aborter.id = id; - aborter.moveToThread(&thread); - connect(&thread, SIGNAL(started()), &aborter, SLOT(abort())); - //it is assumed that the DNS request/response in the backend is slower than it takes to schedule the thread and call abort - thread.start(); - QVERIFY(thread.wait(5000)); - QTestEventLoop::instance().enterLoop(5); - QCOMPARE(lookupsDoneCounter, 0); -} - QTEST_MAIN(tst_QHostInfo) #include "tst_qhostinfo.moc" diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index d95f2fa546..b823b87125 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -404,8 +404,8 @@ void tst_QSslSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthent void tst_QSslSocket::constructing() { - const char readNotOpenMessage[] = "QIODevice::read: device not open"; - const char writeNotOpenMessage[] = "QIODevice::write: device not open"; + const char readNotOpenMessage[] = "QIODevice::read (QSslSocket): device not open"; + const char writeNotOpenMessage[] = "QIODevice::write (QSslSocket): device not open"; if (!QSslSocket::supportsSsl()) return; @@ -443,13 +443,13 @@ void tst_QSslSocket::constructing() QCOMPARE(socket.read(0, 0), qint64(-1)); QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); QVERIFY(socket.readAll().isEmpty()); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine: Called with maxSize < 2"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine (QSslSocket): Called with maxSize < 2"); QCOMPARE(socket.readLine(0, 0), qint64(-1)); char buf[10]; QCOMPARE(socket.readLine(buf, sizeof(buf)), qint64(-1)); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek: Cannot call seek on a sequential device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek (QSslSocket): Cannot call seek on a sequential device"); QVERIFY(!socket.reset()); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek: Cannot call seek on a sequential device"); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek (QSslSocket): Cannot call seek on a sequential device"); QVERIFY(!socket.seek(2)); QCOMPARE(socket.size(), qint64(0)); QVERIFY(!socket.waitForBytesWritten(10)); diff --git a/tests/auto/other/baselineexample/baselineexample.pro b/tests/auto/other/baselineexample/baselineexample.pro deleted file mode 100644 index c1c4b31bfe..0000000000 --- a/tests/auto/other/baselineexample/baselineexample.pro +++ /dev/null @@ -1,19 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2010-12-09T14:55:13 -# -#------------------------------------------------- - -QT += testlib widgets - -TARGET = tst_baselineexample -CONFIG += console -CONFIG -= app_bundle - -TEMPLATE = app - -SOURCES += tst_baselineexample.cpp -DEFINES += SRCDIR=\\\"$$PWD/\\\" - -include($$PWD/../../../baselineserver/shared/qbaselinetest.pri) -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/other/baselineexample/tst_baselineexample.cpp b/tests/auto/other/baselineexample/tst_baselineexample.cpp deleted file mode 100644 index 9059989015..0000000000 --- a/tests/auto/other/baselineexample/tst_baselineexample.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -class tst_BaselineExample : public QObject -{ - Q_OBJECT - -public: - tst_BaselineExample(); - -private Q_SLOTS: - void testBasicUsage(); - void testMultipleImages(); - void testDataDriven_data(); - void testDataDriven(); - void testDataDrivenChecksum_data(); - void testDataDrivenChecksum(); -}; - - -tst_BaselineExample::tst_BaselineExample() -{ -} - - -void tst_BaselineExample::testBasicUsage() -{ - // Generate an image: - QPushButton b("Press me!"); - b.resize(100, 50); - b.show(); - QVERIFY(QTest::qWaitForWindowExposed(&b)); - QImage img1 = b.grab().toImage(); - QVERIFY(!img1.isNull()); - - // Compare it to baseline on server: - QBASELINE_CHECK(img1, "button"); -} - - -void tst_BaselineExample::testMultipleImages() -{ - QPushButton b("Press me!"); - b.resize(100, 50); - b.show(); - QVERIFY(QTest::qWaitForWindowExposed(&b)); - QBASELINE_CHECK(b.grab().toImage(), "text1"); - - b.setText("Kick me!"); - QTest::qWait(50); - QBASELINE_CHECK(b.grab().toImage(), "text2"); -} - - -void tst_BaselineExample::testDataDriven_data() -{ - QTest::addColumn("label"); - QBaselineTest::newRow("short") << "Ok!"; - QBaselineTest::newRow("long") << "A really long button text that just does not seem to end"; - QBaselineTest::newRow("empty") << ""; - QBaselineTest::newRow("signs") << "!@#$%^&*()_"; - QBaselineTest::newRow("html") << "BOLD"; -} - - -void tst_BaselineExample::testDataDriven() -{ - QFETCH(QString, label); - QPushButton b(label); - b.resize(100, 50); - b.show(); - QVERIFY(QTest::qWaitForWindowExposed(&b)); - QBASELINE_TEST(b.grab().toImage()); -} - - -void tst_BaselineExample::testDataDrivenChecksum_data() -{ - QTest::addColumn("label"); - - const int numItems = 5; - const char *tags[numItems] = {"short", "long", "empty", "signs", "html"}; - const char *labels[numItems] = {"Ok!", "A really long button text that just does not seem to end", "", "!@#$%^&*()_", "BOLD"}; - - for (int i = 0; i +#include +#include + +class tst_Blacklisted : public QObject +{ + Q_OBJECT + +private slots: + void pass(); + void skip(); + void fail(); + void xfail(); + void xpass(); + + // This test function must be last, as it calls qFatal(). + void messages(); +}; + +// All the tests below have been blacklisted in blacklisted/BLACKLIST + +void tst_Blacklisted::pass() +{ + QVERIFY(true); +} + +void tst_Blacklisted::skip() +{ + QSKIP("This test should SKIP"); +} + +void tst_Blacklisted::fail() +{ + QVERIFY2(false, "This test should BFAIL"); +} + +void tst_Blacklisted::xfail() +{ + QEXPECT_FAIL("", "This test should XFAIL then BFAIL", Abort); + QVERIFY(false); +} + +void tst_Blacklisted::xpass() +{ + QEXPECT_FAIL("", "This test should XPASS", Abort); + QVERIFY2(true, "This test should XPASS, blacklist ignored for XPASS"); +} + +void tst_Blacklisted::messages() +{ + qWarning("This is a warning that should not appear in silent test output"); + QWARN("This is an internal testlib warning that should not appear in silent test output"); + qDebug("This is a debug message that should not appear in silent test output"); + qCritical("This is a critical message that should not appear in silent test output"); + qInfo("This is an info message that should not appear in silent test output"); + QTestLog::info("This is an internal testlib info message that should not appear in silent test output", __FILE__, __LINE__); + qFatal("This is a fatal error message that should still appear in silent test output"); +} + +QTEST_MAIN(tst_Blacklisted) +#include "tst_blacklisted.moc" diff --git a/tests/auto/testlib/selftests/expected_blacklisted.txt b/tests/auto/testlib/selftests/expected_blacklisted.txt new file mode 100644 index 0000000000..3afd93b0cc --- /dev/null +++ b/tests/auto/testlib/selftests/expected_blacklisted.txt @@ -0,0 +1,26 @@ +********* Start testing of tst_Blacklisted ********* +Config: Using QtTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HERE@ +PASS : tst_Blacklisted::initTestCase() +BPASS : tst_Blacklisted::pass() +SKIP : tst_Blacklisted::skip() This test should SKIP + Loc: [tst_blacklisted.cpp(62)] +BFAIL : tst_Blacklisted::fail() 'false' returned FALSE. (This test should BFAIL) + Loc: [tst_blacklisted.cpp(67)] +XFAIL : tst_Blacklisted::xfail() This test should XFAIL then BFAIL + Loc: [tst_blacklisted.cpp(73)] +BPASS : tst_Blacklisted::xfail() +XPASS : tst_Blacklisted::xpass() 'true' returned TRUE unexpectedly. (This test should XPASS, blacklist ignored for XPASS) + Loc: [tst_blacklisted.cpp(79)] +QWARN : tst_Blacklisted::messages() This is a warning that should not appear in silent test output +WARNING: tst_Blacklisted::messages() This is an internal testlib warning that should not appear in silent test output + Loc: [tst_blacklisted.cpp(85)] +QDEBUG : tst_Blacklisted::messages() This is a debug message that should not appear in silent test output +QSYSTEM: tst_Blacklisted::messages() This is a critical message that should not appear in silent test output +QINFO : tst_Blacklisted::messages() This is an info message that should not appear in silent test output +INFO : tst_Blacklisted::messages() This is an internal testlib info message that should not appear in silent test output + Loc: [tst_blacklisted.cpp(89)] +QFATAL : tst_Blacklisted::messages() This is a fatal error message that should still appear in silent test output +BFAIL : tst_Blacklisted::messages() Received a fatal error. + Loc: [Unknown file(0)] +Totals: 1 passed, 1 failed, 1 skipped, 4 blacklisted +********* Finished testing of tst_Blacklisted ********* diff --git a/tests/auto/testlib/selftests/selftests.pri b/tests/auto/testlib/selftests/selftests.pri index 7b706735a9..7404a1c49b 100644 --- a/tests/auto/testlib/selftests/selftests.pri +++ b/tests/auto/testlib/selftests/selftests.pri @@ -8,6 +8,7 @@ SUBPROGRAMS = \ benchliboptions \ benchlibtickcounter \ benchlibwalltime \ + blacklisted \ cmptest \ commandlinedata \ counting \ diff --git a/tests/auto/testlib/selftests/selftests.qrc b/tests/auto/testlib/selftests/selftests.qrc index ba567f1fb4..715e255e76 100644 --- a/tests/auto/testlib/selftests/selftests.qrc +++ b/tests/auto/testlib/selftests/selftests.qrc @@ -151,5 +151,6 @@ expected_xunit.txt expected_xunit.xml expected_xunit.xunitxml + expected_blacklisted.txt diff --git a/tests/auto/testlib/selftests/tst_selftests.cpp b/tests/auto/testlib/selftests/tst_selftests.cpp index a5840d16d2..5e97a9cfe4 100644 --- a/tests/auto/testlib/selftests/tst_selftests.cpp +++ b/tests/auto/testlib/selftests/tst_selftests.cpp @@ -352,6 +352,7 @@ void tst_Selftests::runSubTest_data() << "benchlibcounting" << "benchlibeventcounter" << "benchliboptions" + << "blacklisted" << "cmptest" << "commandlinedata" << "counting" @@ -470,6 +471,9 @@ void tst_Selftests::runSubTest_data() if (subtest == "benchliboptions") { continue; } + if (subtest == "blacklisted") { + continue; + } if (subtest == "printdatatags") { continue; } @@ -503,7 +507,8 @@ void tst_Selftests::runSubTest_data() const bool crashes = subtest == QLatin1String("assert") || subtest == QLatin1String("exceptionthrow") || subtest == QLatin1String("fetchbogus") || subtest == QLatin1String("crashedterminate") - || subtest == QLatin1String("crashes") || subtest == QLatin1String("silent"); + || subtest == QLatin1String("crashes") || subtest == QLatin1String("silent") + || subtest == QLatin1String("blacklisted"); QTest::newRow(qPrintable(QString("%1 %2").arg(subtest).arg(loggerSet.name))) << subtest << loggers @@ -612,6 +617,7 @@ void tst_Selftests::doRunSubTest(QString const& subdir, QStringList const& logge && subdir != QLatin1String("fetchbogus") && subdir != QLatin1String("xunit") #ifdef Q_CC_MINGW + && subdir != QLatin1String("blacklisted") // calls qFatal() && subdir != QLatin1String("silent") // calls qFatal() #endif && subdir != QLatin1String("benchlibcallgrind")) diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 00e5c60b29..350c6142d2 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -87,6 +87,18 @@ struct QTBUG_31218_Derived : QTBUG_31218<-1<0> {}; class QTBUG_45790 : Bug() { }; #endif +class CreatableGadget +{ + Q_GADGET +public: + Q_INVOKABLE CreatableGadget() + { + CreatableGadget::qt_static_metacall((QObject*)this, QMetaObject::ReadProperty, -1, Q_NULLPTR); + } +}; + +CreatableGadget creatableGadget; // Force the compiler to use the constructor + struct MyStruct {}; struct MyStruct2 {}; @@ -680,7 +692,7 @@ void tst_Moc::oldStyleCasts() QStringList args; args << "-c" << "-x" << "c++" << "-Wold-style-cast" << "-I" << "." - << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", args); QVERIFY(proc.waitForStarted()); proc.write(mocOut); @@ -750,7 +762,7 @@ void tst_Moc::inputFileNameWithDotsButNoExtension() QStringList args; args << "-c" << "-x" << "c++" << "-I" << ".." - << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", args); QVERIFY(proc.waitForStarted()); proc.write(mocOut); @@ -1029,7 +1041,7 @@ void tst_Moc::ignoreOptionClashes() // If -pthread wasn't ignored, it was parsed as a prefix of "thread/", which breaks compilation. QStringList gccArgs; gccArgs << "-c" << "-x" << "c++" << "-I" << ".." - << "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIE" << "-"; + << "-I" << qtIncludePath << "-I" << includeDir << "-o" << "/dev/null" << "-fPIC" << "-"; proc.start("gcc", gccArgs); QVERIFY(proc.waitForStarted()); proc.write(mocOut); @@ -1870,6 +1882,13 @@ void tst_Moc::warnings_data() << 1 << QString() << QString("standard input:5: Error: Class declaration lacks Q_OBJECT macro."); + + QTest::newRow("QTBUG-46210: crash on invalid macro") + << QByteArray("#define Foo(a, b, c) a b c #a #b #c a##b##c #d\n Foo(45);") + << QStringList() + << 1 + << QString("IGNORE_ALL_STDOUT") + << QString(":2: Error: '#' is not followed by a macro parameter"); } void tst_Moc::warnings() diff --git a/tests/auto/tools/qmake/testdata/comments/comments.pro b/tests/auto/tools/qmake/testdata/comments/comments.pro deleted file mode 100644 index 510ab95ab3..0000000000 --- a/tests/auto/tools/qmake/testdata/comments/comments.pro +++ /dev/null @@ -1,31 +0,0 @@ -LIST = 1 2 3 4 #a comment -!equals( LIST, 1 2 3 4 ) { - message( "FAILED: inline comment" ) -} - -LIST = 1 \ - 2 \ -# 3 \ - 4 -!equals( LIST, 1 2 4 ) { - message( "FAILED: commented out continuation" ) -} - -LIST = 1 \ - 2 \#comment - 3 \ - 4 -!equals( LIST, 1 2 3 4 ) { - message( "FAILED: comment at end of continuation") -} - - -LIST = 1 2 3 4#comment -!equals( LIST, 1 2 3 4 ) { - message( "FAILED: no space before comment" ) -} - -LIST = 1 2 3 4$${LITERAL_HASH}five -!equals( LIST, 1 2 3 4$${LITERAL_HASH}five ) { - message( "FAILED: using LITERAL_HASH" ) -} diff --git a/tests/auto/tools/qmake/testdata/func_export/func_export.pro b/tests/auto/tools/qmake/testdata/func_export/func_export.pro deleted file mode 100644 index fc3818985b..0000000000 --- a/tests/auto/tools/qmake/testdata/func_export/func_export.pro +++ /dev/null @@ -1,19 +0,0 @@ -defineTest(doExport) { - EXPORTED += $$1 - export(EXPORTED) -} - -defineTest(callDoExport) { - doExport(bar) - doExport(baz) - EXPORTED = oink - !isEqual(EXPORTED, "oink") { - message( "FAILED: function-scope exports [$$EXPORTED] != oink" ) - } -} - -doExport(foo) -callDoExport() -!isEqual(EXPORTED, "foo bar baz") { - message( "FAILED: global-scope exports [$$EXPORTED] != foo bar baz" ) -} diff --git a/tests/auto/tools/qmake/testdata/func_variables/func_variables.pro b/tests/auto/tools/qmake/testdata/func_variables/func_variables.pro deleted file mode 100644 index cc13437f4a..0000000000 --- a/tests/auto/tools/qmake/testdata/func_variables/func_variables.pro +++ /dev/null @@ -1,49 +0,0 @@ -defineTest(testVariable) { - varname=$$1 - value=$$eval($$varname) - RESULT=$$value - export(RESULT) -} - -defineTest(callTest) { - myvar=$$1 - testVariable(myvar) -} - -defineTest(callTestExport) { - myvar=$$1 - export(myvar) - testVariable(myvar) -} - -defineTest(callTestExportChange) { - myvar=foo - export(myvar) - myvar=$$1 - testVariable(myvar) -} - -value=direct -myvar=$$value -testVariable(myvar) -!isEqual(RESULT,$$value) { - message( "FAILED: result [$$RESULT] != $$value" ) -} - -value=export -callTestExport($$value) -!isEqual(RESULT,$$value) { - message( "FAILED: result [$$RESULT] != $$value" ) -} - -value=export_and_change -callTestExportChange($$value) -!isEqual(RESULT,$$value) { - message( "FAILED: result [$$RESULT] != $$value" ) -} - -value=local -callTest($$value) -!isEqual(RESULT,$$value) { - message( "FAILED: result [$$RESULT] != $$value" ) -} diff --git a/tests/auto/tools/qmake/testdata/functions/functions.pro b/tests/auto/tools/qmake/testdata/functions/functions.pro deleted file mode 100644 index 5db8036188..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/functions.pro +++ /dev/null @@ -1,184 +0,0 @@ -VAR = qt thread - -defineTest(testReplace) { - !isEqual(1, $$2):message("FAILED: $$3: got $$1, expected $${2}.") -} - -#count -!count( VAR, 2 ) { - message( "FAILED: count function: $$VAR" ) -} - -#contains -!contains( VAR, thread ) { - message( "FAILED: contains function: $$VAR" ) -} - -#exists -!exists( functions.pro ) { - message( "FAILED: exists function" ) -} - -#isEmpty -isEmpty( VAR ) { - message( "FAILED: isEmpty function: $VAR" ) -} - -#files -!equals($$list($$files(one/*.cpp)), "one/1.cpp one/2.cpp") { - message( "FAILED: files function: one/*.cpp" ) -} -!equals($$list($$files(one/1*.cpp)), "one/1.cpp") { - message( "FAILED: files function: one/1*.cpp" ) -} -!equals($$list($$files(two/*.cpp)), "two/1.cpp two/2.cpp") { - message( "FAILED: files function: two/*.cpp" ) -} -!equals($$list($$files(three/wildcard*.cpp)), "three/wildcard21.cpp three/wildcard22.cpp") { - message( "FAILED: files function: three/wildcard*.cpp" ) -} -!equals($$list($$files(*.cpp)), "1.cpp 2.cpp wildcard21.cpp wildcard22.cpp") { - message( "FAILED: files function: *.cpp" ) -} -!equals($$list($$files(wildcard*.cpp)), "wildcard21.cpp wildcard22.cpp") { - message( "FAILED: files function: wildcard*.cpp" ) -} - -#infile -!infile( infiletest.pro, DEFINES, QT_DLL ){ - message( "FAILED: infile function" ) -} - -#include -include( infiletest.pro, "", true ) -!contains( DEFINES, QT_DLL ) { - message( "FAILED: include function: $$DEFINES" ) -} - -#replace -VERSION=1.0.0 -VERSION_replaced=$$replace(VERSION,\\.,_) -!isEqual(VERSION_replaced, 1_0_0) { - message( "FAILED: replace function: $$VERSION_replaced" ) -} - -#test functions -defineTest(myTestFunction) { - RESULT = - list=$$1 - for(l, list) { - RESULT += $$l - } - export(RESULT) -} -myTestFunction(oink baa moo) -!equals($$list($$member(RESULT, 0)), "oink") { - message("FAILED: myTestFunction: $$RESULT") -} -myTestFunction("oink baa" moo) -!equals($$list($$member(RESULT, 0)), "oink baa") { - message("FAILED: myTestFunction: $$RESULT") -} -myTestFunction(oink "baa moo") -!equals($$list($$member(RESULT, 0)), "oink") { - message("FAILED: myTestFunction: $$RESULT") -} -myTestFunction("oink baa moo") -!equals($$list($$member(RESULT, 0)), "oink baa moo") { - message("FAILED: myTestFunction: $$RESULT") -} - -#recursive -defineReplace(myRecursiveReplaceFunction) { - RESULT = - list = $$1 - RESULT += $$member(list, 0) - list -= $$RESULT - !isEmpty(list):RESULT += $$myRecursiveReplaceFunction($$list) - return($$RESULT) -} -RESULT = $$myRecursiveReplaceFunction(oink baa moo) -!isEqual(RESULT, "oink baa moo") { - message( "FAILED: myRecursiveReplaceFunction [$$RESULT] != oink baa moo" ) -} - -moo = "this is a test" "for real" -fn = $$OUT_PWD/testdir/afile -write_file($$fn, moo)|message("FAILED: write_file() failed") -exists($$fn)|message("FAILED: write_file() didn't write anything") -mooout = $$cat($$fn, line) -equals(moo, $$mooout)|message("FAILED: write_file() wrote something wrong") -moo += "another line" -write_file($$fn, moo)|message("FAILED: write_file() failed (take 2)") -mooout = $$cat($$fn, line) -equals(moo, $$mooout)|message("FAILED: write_file() wrote something wrong (take 2)") -mooadd = "yet another line" -write_file($$fn, mooadd, append)|message("FAILED: write_file() failed (append)") -moo += $$mooadd -mooout = $$cat($$fn, line) -equals(moo, $$mooout)|message("FAILED: write_file() wrote something wrong when appending") - -pn = $$OUT_PWD/testpath/subdir -mkpath($$pn)|message("FAILED: mkpath() failed") -exists($$pn)|message("FAILED: mkpath() didn't create anything") - -in = easy "less easy" sca$${LITERAL_HASH}ry crazy$$escape_expand(\\t\\r\\n) $$escape_expand(\\t)shit \'no\"way\\here -out = "easy \"less easy\" sca\$\${LITERAL_HASH}ry crazy\$\$escape_expand(\\\\t\\\\r\\\\n) \$\$escape_expand(\\\\t)shit \\\'no\\\"way\\\\here" -testReplace($$val_escape(in), $$out, "val_escape") - -testReplace($$shadowed($$PWD/something), $$OUT_PWD/something, "shadowed") -testReplace($$shadowed($$PWD), $$OUT_PWD, "shadowed (take 2)") - -#format_number -spc = " " -testReplace($$format_number(13), 13, "simple number format") -testReplace($$format_number(-13), -13, "negative number format") -testReplace($$format_number(13, ibase=16), 19, "hex input number format") -testReplace($$format_number(13, obase=16), d, "hex output number format") -testReplace($$format_number(13, width=5), " $$spc 13", "right aligned number format") -testReplace($$format_number(13, width=5 leftalign), "13 $$spc ", "left aligned number format") -testReplace($$format_number(13, width=5 zeropad), "00013", "zero-padded number format") -testReplace($$format_number(13, width=5 alwayssign), "$$spc +13", "always signed number format") -testReplace($$format_number(13, width=5 alwayssign zeropad), "+0013", "zero-padded always signed number format") -testReplace($$format_number(13, width=5 padsign), " $$spc 13", "sign-padded number format") -testReplace($$format_number(13, width=5 padsign zeropad), " 0013", "zero-padded sign-padded number format") - -testReplace($$clean_path("c:$${DIR_SEPARATOR}crazy//path/../trolls"), "c:/crazy/trolls", "clean_path") - -testReplace($$shell_path("/crazy/trolls"), "$${QMAKE_DIR_SEP}crazy$${QMAKE_DIR_SEP}trolls", "shell_path") -testReplace($$system_path("/crazy/trolls"), "$${DIR_SEPARATOR}crazy$${DIR_SEPARATOR}trolls", "system_path") - -testReplace($$absolute_path("crazy/trolls"), "$$PWD/crazy/trolls", "absolute_path") -testReplace($$absolute_path("crazy/trolls", "/fake/path"), "/fake/path/crazy/trolls", "absolute_path with base") -testReplace($$absolute_path(""), "$$PWD", "absolute_path of empty") -testReplace($$relative_path($$_PRO_FILE_PWD_), $$basename($$_PRO_FILE_), "relative_path") -testReplace($$relative_path("/fake/trolls", "/fake/path"), "../trolls", "relative_path with base") -testReplace($$relative_path(""), "", "relative_path of empty") - -#this test is very rudimentary. the backend function is thoroughly tested in qt creator -in = "some nasty & ugly\" path & thing\\" -out_cmd = "\"some nasty & ugly\\\" path ^& thing\\\\^\"" -out_sh = "'some nasty & ugly\" path & thing\\'" -equals(QMAKE_HOST.os, Windows): \ - out = $$out_cmd -else: \ - out = $$out_sh -testReplace($$system_quote($$in), $$out, "system_quote") -!equals(QMAKE_DIR_SEP, /): \ - out = $$out_cmd -else: \ - out = $$out_sh -testReplace($$shell_quote($$in), $$out, "shell_quote") - -testReplace($$reverse($$list(one two three)), three two one, "reverse") - -testReplace($$cat(textfile), hi '"holla he"' 'hu!') - -MOD.a.depends = -MOD.b.depends = -MOD.b.priority = 1 -MOD.c.depends = a b -testReplace($$resolve_depends($$list(c), "MOD."), c b a) -MOD.a.priority = 1 -MOD.b.priority = 0 -testReplace($$resolve_depends($$list(c), "MOD."), c a b) diff --git a/tests/auto/tools/qmake/testdata/functions/one/1.cpp b/tests/auto/tools/qmake/testdata/functions/one/1.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/one/1.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/textfile b/tests/auto/tools/qmake/testdata/functions/textfile deleted file mode 100644 index a8248ed6f8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/textfile +++ /dev/null @@ -1 +0,0 @@ -hi "holla he" hu! diff --git a/tests/auto/tools/qmake/testdata/functions/three/wildcard21.cpp b/tests/auto/tools/qmake/testdata/functions/three/wildcard21.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/three/wildcard21.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/three/wildcard22.cpp b/tests/auto/tools/qmake/testdata/functions/three/wildcard22.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/three/wildcard22.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/two/1.cpp b/tests/auto/tools/qmake/testdata/functions/two/1.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/two/1.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/two/2.cpp b/tests/auto/tools/qmake/testdata/functions/two/2.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/two/2.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/wildcard21.cpp b/tests/auto/tools/qmake/testdata/functions/wildcard21.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/wildcard21.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/functions/wildcard22.cpp b/tests/auto/tools/qmake/testdata/functions/wildcard22.cpp deleted file mode 100644 index 8bdc2e59e8..0000000000 --- a/tests/auto/tools/qmake/testdata/functions/wildcard22.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ diff --git a/tests/auto/tools/qmake/testdata/include_function/existing_file.pri b/tests/auto/tools/qmake/testdata/include_function/existing_file.pri deleted file mode 100644 index 8b9aaca340..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/existing_file.pri +++ /dev/null @@ -1,3 +0,0 @@ -QT = -CONFIG = console -SOURCES = main.cpp diff --git a/tests/auto/tools/qmake/testdata/include_function/include_existing_file.pro b/tests/auto/tools/qmake/testdata/include_function/include_existing_file.pro deleted file mode 100644 index 424062a9ac..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/include_existing_file.pro +++ /dev/null @@ -1,7 +0,0 @@ -# Test to see if include(), by default, succeeds when the specific file -# to include exists -include(existing_file.pri) - -# Test to see if by specifying full set of parameters to include() -# succeeds when the specified filed to include exists -include(existing_file.pri, "", false) diff --git a/tests/auto/tools/qmake/testdata/include_function/include_missing_file.pro b/tests/auto/tools/qmake/testdata/include_function/include_missing_file.pro deleted file mode 100644 index 0b59981240..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/include_missing_file.pro +++ /dev/null @@ -1,3 +0,0 @@ -# Test to see if include(), by default, fails when the specific file -# to include does not exist -include(missing_file.pri) diff --git a/tests/auto/tools/qmake/testdata/include_function/include_missing_file2.pro b/tests/auto/tools/qmake/testdata/include_function/include_missing_file2.pro deleted file mode 100644 index 542b9ff516..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/include_missing_file2.pro +++ /dev/null @@ -1,3 +0,0 @@ -# Specifying full set of parameters to include() to test that a warning -# is shown for this non-existing file. -include(missing_file.pri, "", false) diff --git a/tests/auto/tools/qmake/testdata/include_function/main.cpp b/tests/auto/tools/qmake/testdata/include_function/main.cpp deleted file mode 100644 index 68e9c98e77..0000000000 --- a/tests/auto/tools/qmake/testdata/include_function/main.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -int main(int /*argc*/, char ** /*argv*/) -{ - return 0; -} diff --git a/tests/auto/tools/qmake/testdata/json/json.pro b/tests/auto/tools/qmake/testdata/json/json.pro deleted file mode 100644 index 33440b3209..0000000000 --- a/tests/auto/tools/qmake/testdata/json/json.pro +++ /dev/null @@ -1,26 +0,0 @@ -jsontext = $$cat($$PWD/test.json) -parseJson(jsontext, json) - -# print all keys -message(json._KEYS_ $${json._KEYS_}) - -# print array -message(json.array._KEYS_ $${json.array._KEYS_}) -for(key, json.array._KEYS_): \ - message(json.array.$${key} $$eval(json.array.$${key})) - -# print object -message(json.object._KEYS_ $${json.object._KEYS_}) -for(key, json.object._KEYS_): \ - message(json.object.$${key} $$eval(json.object.$${key})) - -# print value tyes -message(json.string: $${json.string}) -message(json.number: $${json.number}) -message(json.true: $${json.true}) -message(json.false: $${json.false}) -message(json.null: $${json.null}) - -# check that booleans work -$${json.true}: message(json.true is true) -!$${json.false}: message(json.false is false) diff --git a/tests/auto/tools/qmake/testdata/json/test.json b/tests/auto/tools/qmake/testdata/json/test.json deleted file mode 100644 index cc82908eba..0000000000 --- a/tests/auto/tools/qmake/testdata/json/test.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "array" : ["arrayItem1", "arrayItem2", "arrayItem3"], - "object" : { "key1" : "objectValue1", "key2" : "objectValue2" }, - "string" : "test string", - "number" : 999, - "true" : true, - "false" :false, - "null" : null -} diff --git a/tests/auto/tools/qmake/testdata/operators/operators.pro b/tests/auto/tools/qmake/testdata/operators/operators.pro deleted file mode 100644 index 463fa73d81..0000000000 --- a/tests/auto/tools/qmake/testdata/operators/operators.pro +++ /dev/null @@ -1,23 +0,0 @@ -VAR = qt thread - -VAR += debug -!contains( VAR, debug ) { - message( "FAILED: +=" ) -} - -VAR -= thread -contains( VAR, thread ) { - message( "FAILED: -=" ) -} - -VAR = thread -VAR *= thread -!count( VAR, 1 ) { - message( "FAILED: *=" ) -} - -VAR = thread QT_DLL debug -VAR ~= s/QT_+/Q_ -!contains( VAR, Q_DLL ) { - message( "FAILED: ~=" ) -} diff --git a/tests/auto/tools/qmake/testdata/variables/variables.pro b/tests/auto/tools/qmake/testdata/variables/variables.pro deleted file mode 100644 index e4b9eaa884..0000000000 --- a/tests/auto/tools/qmake/testdata/variables/variables.pro +++ /dev/null @@ -1,12 +0,0 @@ -VAR = 1 2 3 4 5 -JOINEDVAR = $$join( VAR, "-GLUE-", "-BEFORE-", "-AFTER-" ) -!contains( JOINEDVAR, -BEFORE-1-GLUE-2-GLUE-3-GLUE-4-GLUE-5-AFTER- ) { - message( "FAILED: join [$$JOINEDVAR != -BEFORE-1-GLUE-2-GLUE-3-GLUE-4-GLUE-5-AFTER-]" ) -} - -# To test member we need to use join -NEWVAR = $$member( VAR, 4 ) $$member( VAR, 3 ) $$member( VAR, 2 ) -JOINEDNEWVAR = $$join( NEWVAR, "-" ) -!contains( JOINEDNEWVAR, 5-4-3 ) { - message( "FAILED: member [$$JOINEDNEWVAR != 5-4-3]" ) -} diff --git a/tests/auto/tools/qmake/tst_qmake.cpp b/tests/auto/tools/qmake/tst_qmake.cpp index 48c6c0ac84..ac94d1a2b9 100644 --- a/tests/auto/tools/qmake/tst_qmake.cpp +++ b/tests/auto/tools/qmake/tst_qmake.cpp @@ -68,12 +68,6 @@ private slots: void simple_dll(); void subdirs(); void subdir_via_pro_file_extra_target(); - void functions(); - void operators(); - void variables(); - void func_export(); - void func_variables(); - void comments(); void duplicateLibraryEntries(); void export_across_file_boundaries(); void include_dir(); @@ -88,11 +82,9 @@ private slots: #if defined(Q_OS_MAC) void bundle_spaces(); #endif - void includefunction(); void substitutes(); void project(); void proFileCache(); - void json(); void resources(); private: @@ -262,43 +254,6 @@ void tst_qmake::subdir_via_pro_file_extra_target() QVERIFY( test_compiler.make( workDir, "extratarget" )); } -void tst_qmake::functions() -{ - QString workDir = base_path + "/testdata/functions"; - QString buildDir = base_path + "/testdata/functions_build"; - QVERIFY( test_compiler.qmake( workDir, "functions", buildDir )); -} - -void tst_qmake::operators() -{ - QString workDir = base_path + "/testdata/operators"; - QVERIFY( test_compiler.qmake( workDir, "operators" )); -} - -void tst_qmake::variables() -{ - QString workDir = base_path + "/testdata/variables"; - QVERIFY(test_compiler.qmake( workDir, "variables" )); -} - -void tst_qmake::func_export() -{ - QString workDir = base_path + "/testdata/func_export"; - QVERIFY(test_compiler.qmake( workDir, "func_export" )); -} - -void tst_qmake::func_variables() -{ - QString workDir = base_path + "/testdata/func_variables"; - QVERIFY(test_compiler.qmake( workDir, "func_variables" )); -} - -void tst_qmake::comments() -{ - QString workDir = base_path + "/testdata/comments"; - QVERIFY(test_compiler.qmake( workDir, "comments" )); -} - void tst_qmake::duplicateLibraryEntries() { QVERIFY(true); @@ -499,26 +454,6 @@ void tst_qmake::bundle_spaces() } #endif // defined(Q_OS_MAC) -void tst_qmake::includefunction() -{ - QString workDir = base_path + "/testdata/include_function"; - QRegExp warningMsg("Cannot read .*: No such file or directory"); - QVERIFY(test_compiler.qmake( workDir, "include_existing_file")); - QVERIFY(!test_compiler.commandOutput().contains(warningMsg)); - - // test include() usage on a missing file - test_compiler.clearCommandOutput(); - workDir = base_path + "/testdata/include_function"; - QVERIFY(test_compiler.qmake( workDir, "include_missing_file" )); - QVERIFY(test_compiler.commandOutput().contains(warningMsg)); - - // test include() usage on a missing file when all function parameters are used - test_compiler.clearCommandOutput(); - workDir = base_path + "/testdata/include_function"; - QVERIFY(test_compiler.qmake( workDir, "include_missing_file2" )); - QVERIFY(test_compiler.commandOutput().contains(warningMsg)); -} - void tst_qmake::substitutes() { QString workDir = base_path + "/testdata/substitutes"; @@ -564,34 +499,6 @@ void tst_qmake::proFileCache() QVERIFY( test_compiler.qmake( workDir, "pro_file_cache" )); } -void tst_qmake::json() -{ - QString workDir = base_path + "/testdata/json"; - QVERIFY( test_compiler.qmake( workDir, "json.pro" )); - QString output = test_compiler.commandOutput(); - - // all keys - QVERIFY(output.contains("json._KEYS_ array false null number object string true")); - // array - QVERIFY(output.contains("json.array._KEYS_ 0 1 2")); - QVERIFY(output.contains("json.array.0 arrayItem1")); - QVERIFY(output.contains("json.array.1 arrayItem2")); - QVERIFY(output.contains("json.array.2 arrayItem3")); - // object - QVERIFY(output.contains("json.object._KEYS_ key1 key2")); - QVERIFY(output.contains("json.object.key1 objectValue1")); - QVERIFY(output.contains("json.object.key1 objectValue1")); - // value types - QVERIFY(output.contains("json.string: test string")); - QVERIFY(output.contains("json.number: 999")); - QVERIFY(output.contains("json.true: true")); - QVERIFY(output.contains("json.false: false")); - QVERIFY(output.contains("json.null:")); - // functional booleans - QVERIFY(output.contains("json.true is true")); - QVERIFY(output.contains("json.false is false")); -} - void tst_qmake::resources() { QString workDir = base_path + "/testdata/resources"; diff --git a/tests/auto/tools/qmakelib/evaltest.cpp b/tests/auto/tools/qmakelib/evaltest.cpp new file mode 100644 index 0000000000..fab2cdce17 --- /dev/null +++ b/tests/auto/tools/qmakelib/evaltest.cpp @@ -0,0 +1,2513 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tst_qmakelib.h" + +#include +#include +#include +#include +#include + +void tst_qmakelib::addAssignments() +{ + QTest::newRow("assignment") + << "VAR = foo bar baz" + << "VAR = foo bar baz" + << "" + << true; + + QTest::newRow("appending") + << "VAR = foo bar baz\nVAR += foo gaz gaz" + << "VAR = foo bar baz foo gaz gaz" + << "" + << true; + + QTest::newRow("unique appending") + << "VAR = foo bar baz\nVAR *= foo gaz gaz" + << "VAR = foo bar baz gaz" + << "" + << true; + + QTest::newRow("removing") + << "VAR = foo bar foo baz\nVAR -= foo gaz gaz" + << "VAR = bar baz" + << "" + << true; + + // Somewhat unexpectedly, the g modifier is implicit within each element. + QTest::newRow("replacing") + << "VAR = foo bar foo baz\nVAR ~= s,o,0," + << "VAR = f00 bar foo baz" + << "" + << true; + + // Consistently with the "there are no empty elements", what becomes empty gets zapped. + QTest::newRow("replacing with nothing") + << "VAR = foo bar foo baz\nVAR ~= s,foo,," + << "VAR = bar foo baz" + << "" + << true; + + QTest::newRow("replacing case-insensitively") + << "VAR = foO bar foo baz\nVAR ~= s,o,0,i" + << "VAR = f00 bar foo baz" + << "" + << true; + + // In all elements, not all within each/one/??? element. + QTest::newRow("replacing globally") + << "VAR = foo bar foo baz\nVAR ~= s,o,0,g" + << "VAR = f00 bar f00 baz" + << "" + << true; + + // Replacing with the same string counts as no match. + // This is rather questionable ... + QTest::newRow("replacing with same") + << "VAR = foo bar foo baz\nVAR ~= s,ba[rz],bar," + << "VAR = foo bar foo bar" + << "" + << true; + + QTest::newRow("replacing with auto-quote") + << "VAR = foo [bar] foo baz\nVAR ~= s,[bar],bar,q" + << "VAR = foo bar foo baz" + << "" + << true; + + QTest::newRow("replacing with expansions") + << "VAR = foo bar foo baz\nPAT = foo\nREPL = 'yee haw'\nVAR ~= s,$$PAT,$$REPL," + << "VAR = 'yee haw' bar foo baz" + << "" + << true; + + QTest::newRow("~= with bad function") + << "VAR ~= m/foo/" + << "" + << "##:1: The ~= operator can handle only the s/// function." + << true; // rather questionable + + QTest::newRow("~= s with bad number of arguments") + << "VAR ~= s/bla\nVAR ~= s/bla/foo//" + << "" + << "##:1: The s/// function expects 3 or 4 arguments.\n" + "##:2: The s/// function expects 3 or 4 arguments." + << true; // rather questionable +} + +void tst_qmakelib::addExpansions() +{ + QTest::newRow("expand variable") + << "V1 = foo\nVAR = $$V1" + << "VAR = foo" + << "" + << true; + + QTest::newRow("expand property") + << "VAR = $$[P1]" + << "VAR = 'prop val'" + << "" + << true; + + QTest::newRow("expand environment variable") + << "VAR = $$(E1)" + << "VAR = 'env var'" + << "" + << true; + + // These test addStr/addStr. + + QTest::newRow("expand: str $$(env)") + << "VAR = foo $$(E1)" + << "VAR = foo 'env var'" + << "" + << true; + + QTest::newRow("expand: str$$(env)") + << "VAR = foo$$(E1)" + << "VAR = 'fooenv var'" + << "" + << true; + + QTest::newRow("expand: 'str $$(env)'") + << "VAR = 'foo $$(E1)'" + << "VAR = 'foo env var'" + << "" + << true; + + // These test addStr/addStrList + + QTest::newRow("expand: str $$var") + << "V1 = foo barbaz\nVAR = str $$V1" + << "VAR = str foo barbaz" + << "" + << true; + + QTest::newRow("expand: $$var str") + << "V1 = foo barbaz\nVAR = $$V1 str" + << "VAR = foo barbaz str" + << "" + << true; + + QTest::newRow("expand: str$$var") + << "V1 = foo barbaz\nVAR = str$$V1" + << "VAR = strfoo barbaz" + << "" + << true; + + QTest::newRow("expand: $${var}str") + << "V1 = foo barbaz\nVAR = $${V1}str" + << "VAR = foo barbazstr" + << "" + << true; + + QTest::newRow("expand: 'str $$var'") + << "V1 = foo barbaz\nVAR = 'str $$V1'" + << "VAR = 'str foo barbaz'" + << "" + << true; + + QTest::newRow("expand: '$$var str'") + << "V1 = foo barbaz\nVAR = '$$V1 str'" + << "VAR = 'foo barbaz str'" + << "" + << true; + + // Same again in joined context + + QTest::newRow("expand joined: str $$(env)") + << "VAR = $$quote(foo $$(E1))" + << "VAR = 'foo env var'" + << "" + << true; + + QTest::newRow("expand joined: str$$(env)") + << "VAR = $$quote(foo$$(E1))" + << "VAR = 'fooenv var'" + << "" + << true; + + QTest::newRow("expand joined: 'str $$(env)'") + << "VAR = $$quote('foo $$(E1)')" + << "VAR = 'foo env var'" + << "" + << true; + + QTest::newRow("expand joined: str $$var") + << "V1 = foo barbaz\nVAR = $$quote(str $$V1)" + << "VAR = 'str foo barbaz'" + << "" + << true; + + QTest::newRow("expand joined: $$var str") + << "V1 = foo barbaz\nVAR = $$quote($$V1 str)" + << "VAR = 'foo barbaz str'" + << "" + << true; + + QTest::newRow("expand joined: str$$var") + << "V1 = foo barbaz\nVAR = $$quote(str$$V1)" + << "VAR = 'strfoo barbaz'" + << "" + << true; + + QTest::newRow("expand joined: $${var}str") + << "V1 = foo barbaz\nVAR = $$quote($${V1}str)" + << "VAR = 'foo barbazstr'" + << "" + << true; + + QTest::newRow("expand joined: 'str $$var'") + << "V1 = foo barbaz\nVAR = $$quote('str $$V1')" + << "VAR = 'str foo barbaz'" + << "" + << true; + + QTest::newRow("expand joined: '$$var str'") + << "V1 = foo barbaz\nVAR = $$quote('$$V1 str')" + << "VAR = 'foo barbaz str'" + << "" + << true; + + // Variable expansions on LHS + + QTest::newRow("indirect assign: $$var") + << "V = VAR\n$$V = foo" + << "VAR = foo" + << "" + << true; + + QTest::newRow("indirect assign: fix$$var") + << "V = AR\nV$$V = foo" + << "VAR = foo" + << "" + << true; + + QTest::newRow("indirect assign: $${var}fix") + << "V = VA\n$${V}R = foo" + << "VAR = foo" + << "" + << true; + + QTest::newRow("indirect assign: eval") + << "V = VAR\n$$eval(V) = foo" + << "VAR = foo" + << "" + << true; + + QTest::newRow("indirect assign: multiple") + << "V = FOO BAR\n$$V = foo" + << "" + << "##:2: Left hand side of assignment must expand to exactly one word." + << true; +} + +void tst_qmakelib::addControlStructs() +{ + QTest::newRow("true") + << "true: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false") + << "false: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-config") + << "CONFIG += test\ntest: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false-config") + << "test: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-wildcard") + << "CONFIG += testing\ntest*: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false-wildcard") + << "test*: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-else") + << "true: VAR1 = 1\nelse: VAR2 = 1" + << "VAR1 = 1\nVAR2 = UNDEF" + << "" + << true; + + QTest::newRow("false-else") + << "false: VAR1 = 1\nelse: VAR2 = 1" + << "VAR1 = UNDEF\nVAR2 = 1" + << "" + << true; + + QTest::newRow("true-else-true-else") + << "true: VAR1 = 1\nelse: true: VAR2 = 1\nelse: VAR3 = 1" + << "VAR1 = 1\nVAR2 = UNDEF\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("true-else-false-else") + << "true: VAR1 = 1\nelse: false: VAR2 = 1\nelse: VAR3 = 1" + << "VAR1 = 1\nVAR2 = UNDEF\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("false-else-true-else") + << "false: VAR1 = 1\nelse: true: VAR2 = 1\nelse: VAR3 = 1" + << "VAR1 = UNDEF\nVAR2 = 1\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("false-else-false-else") + << "false: VAR1 = 1\nelse: false: VAR2 = 1\nelse: VAR3 = 1" + << "VAR1 = UNDEF\nVAR2 = UNDEF\nVAR3 = 1" + << "" + << true; + + QTest::newRow("true-{false-else}-else") + << "true {\nfalse: VAR1 = 1\nelse: VAR2 = 1\n}\nelse: VAR3 = 1" + << "VAR1 = UNDEF\nVAR2 = 1\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("NOT-true") + << "!true: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("NOT-false") + << "!false: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("true-AND-true") + << "true:true: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("true-AND-false") + << "true:false: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("false-AND-true") + << "false:true: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("false-OR-false") + << "false|false: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-OR-false") + << "true|false: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false-OR-true") + << "false|true: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("NOT-false-AND-true") + << "!false:true: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("true-AND-message") + << "true:message(hi): VAR = 1" + << "VAR = 1" + << "Project MESSAGE: hi" + << true; + + QTest::newRow("false-AND-message") + << "false:message(hi): VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("true-OR-message") + << "true|message(hi): VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false-OR-message") + << "false|message(hi): VAR = 1" + << "VAR = 1" + << "Project MESSAGE: hi" + << true; + + QTest::newRow("true-OR-message-AND-false") + << "true|message(hi):false: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("false-OR-message-AND-false") + << "false|message(hi):false: VAR = 1" + << "VAR = UNDEF" + << "Project MESSAGE: hi" + << true; + + QTest::newRow("true (indirect)") + << "TEST = true\n$$TEST: VAR = 1" + << "VAR = 1" + << "" + << true; + + QTest::newRow("false (indirect)") + << "TEST = false\n$$TEST: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + // Yes, this is not supposed to work + QTest::newRow("true|false (indirect)") + << "TEST = true|false\n$$TEST: VAR = 1" + << "VAR = UNDEF" + << "" + << true; + + QTest::newRow("for (var, var)") + << "IN = one two three\nfor (IT, IN) { OUT += $$IT }" + << "OUT = one two three" + << "" + << true; + + QTest::newRow("for (var, range)") + << "for (IT, 1..3) { OUT += $$IT }" + << "OUT = 1 2 3" + << "" + << true; + + QTest::newRow("for (var, reverse-range)") + << "for (IT, 3..1) { OUT += $$IT }" + << "OUT = 3 2 1" + << "" + << true; + + // This syntax is rather ridiculous. + QTest::newRow("for (ever)") + << "for (ever) {}" + << "" + << "##:1: Ran into infinite loop (> 1000 iterations)." + << true; + + // This is even worse. + QTest::newRow("for (VAR, forever)") + << "for (VAR, forever) { OUT = $$VAR }" + << "OUT = 999" + << "##:1: Ran into infinite loop (> 1000 iterations)." + << true; + + QTest::newRow("for (garbage)") + << "for (garbage) { OUT = FAIL }" + << "OUT = UNDEF" + << "##:1: Invalid loop expression." + << true; + + QTest::newRow("next()") + << "IN = one two three\nfor (IT, IN) {\nequals(IT, two):next()\nOUT += $$IT\n}" + << "OUT = one three" + << "" + << true; + + QTest::newRow("nested next()") + << "IN = one two three\nfor (IT, IN) {\nfor (NIT, IN):next()\nOUT += $$IT\n}" + << "OUT = one two three" + << "" + << true; + + QTest::newRow("break()") + << "IN = one two three\nfor (IT, IN) {\nequals(IT, three):break()\nOUT += $$IT\n}" + << "OUT = one two" + << "" + << true; + + QTest::newRow("nested break()") + << "IN = one two three\nfor (IT, IN) {\nfor (NIT, IN):break()\nOUT += $$IT\n}" + << "OUT = one two three" + << "" + << true; + + QTest::newRow("defineReplace()") + << "defineReplace(func) { return($$1 + $$2) }\n" + "VAR = $$func(test me, \"foo bar\")" + << "VAR = test me + 'foo bar'" + << "" + << true; + + QTest::newRow("defineTest()") + << "defineTest(func) { return($$1) }\n" + "func(true): VAR += true\n" + "func(false): VAR += false" + << "VAR = true" + << "" + << true; + + QTest::newRow("true-AND-defineTest()") + << "true: defineTest(func)\n" + "defined(func): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("false-AND-defineTest()") + << "false: defineTest(func)\n" + "defined(func): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("true-OR-defineTest()") + << "true| defineTest(func)\n" + "defined(func): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("false-OR-defineTest()") + << "false| defineTest(func)\n" + "defined(func): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("variable scoping") + << "defineTest(func) {\n" + "VAR1 = modified\n!equals(VAR1, modified): return(false)\n" + "VAR2 += modified\n!equals(VAR2, original modified): return(false)\n" + "VAR3 = new var\n!equals(VAR3, new var): return(false)\n" + "return(true)\n" + "}\n" + "VAR1 = pristine\nVAR2 = original\nfunc(): OK = 1" + << "OK = 1\nVAR1 = pristine\nVAR2 = original\nVAR3 = UNDEF" + << "" + << true; + + QTest::newRow("ARGC and ARGS") + << "defineTest(func) {\n" + "export(ARGC)\n" + "export(ARGS)\n" + "}\n" + "func(test me, \"foo bar\")" + << "ARGC = 2\nARGS = test me 'foo bar'" + << "" + << true; + + QTest::newRow("recursion") + << "defineReplace(func) {\n" + "RET = *$$member(1, 0)*\n" + "REST = $$member(1, 1, -1)\n" + "!isEmpty(REST): RET += $$func($$REST)\n" + "return($$RET)\n" + "}\n" + "VAR = $$func(you are ...)" + << "VAR = *you* *are* *...*" + << "" + << true; + + QTest::newRow("top-level return()") + << "VAR = good\nreturn()\nVAR = bad" + << "VAR = good" + << "" + << true; + + QTest::newRow("return() from function") + << "defineTest(func) {\nVAR = good\nexport(VAR)\nreturn()\nVAR = bad\nexport(VAR)\n}\n" + "func()" + << "VAR = good" + << "" + << true; + + QTest::newRow("return() from nested function") + << "defineTest(inner) {\nVAR = initial\nexport(VAR)\nreturn()\nVAR = bad\nexport(VAR)\n}\n" + "defineTest(outer) {\ninner()\nVAR = final\nexport(VAR)\n}\n" + "outer()" + << "VAR = final" + << "" + << true; +} + +void tst_qmakelib::addReplaceFunctions(const QString &qindir) +{ + QTest::newRow("$$member(): empty") + << "IN = \nVAR = $$member(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$member(): too short") + << "IN = one two three\nVAR = $$member(IN, 1, 5)" + << "VAR =" // this is actually kinda stupid + << "" + << true; + + QTest::newRow("$$member(): ok") + << "IN = one two three four five six seven\nVAR = $$member(IN, 1, 4)" + << "VAR = two three four five" + << "" + << true; + + QTest::newRow("$$member(): ok (default start)") + << "IN = one two three\nVAR = $$member(IN)" + << "VAR = one" + << "" + << true; + + QTest::newRow("$$member(): ok (default end)") + << "IN = one two three\nVAR = $$member(IN, 2)" + << "VAR = three" + << "" + << true; + + QTest::newRow("$$member(): negative") + << "IN = one two three four five six seven\nVAR = $$member(IN, -4, -3)" + << "VAR = four five" + << "" + << true; + + QTest::newRow("$$member(): inverse") + << "IN = one two three four five six seven\nVAR = $$member(IN, 4, 1)" + << "VAR = five four three two" + << "" + << true; + + QTest::newRow("$$member(): dots") + << "IN = one two three four five six seven\nVAR = $$member(IN, 1..4)" + << "VAR = two three four five" + << "" + << true; + + QTest::newRow("$$member(): bad number of arguments") + << "VAR = $$member(1, 2, 3, 4)" + << "VAR =" + << "##:1: member(var, start, end) requires one to three arguments." + << true; + + QTest::newRow("$$member(): bad args (1)") + << "IN = one two three\nVAR = $$member(IN, foo, 4)" + << "VAR =" + << "##:2: member() argument 2 (start) 'foo' invalid." + << true; + + QTest::newRow("$$member(): bad args (2)") + << "IN = one two three\nVAR = $$member(IN, foo..4)" + << "VAR =" + << "##:2: member() argument 2 (start) 'foo..4' invalid." + << true; + + QTest::newRow("$$member(): bad args (3)") + << "IN = one two three\nVAR = $$member(IN, 4, foo)" + << "VAR =" + << "##:2: member() argument 3 (end) 'foo' invalid." + << true; + + QTest::newRow("$$member(): bad args (4)") + << "IN = one two three\nVAR = $$member(IN, 4..foo)" + << "VAR =" + << "##:2: member() argument 2 (start) '4..foo' invalid." + << true; + + QTest::newRow("$$first(): empty") + << "IN = \nVAR = $$first(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$first(): one") + << "IN = one\nVAR = $$first(IN)" + << "VAR = one" + << "" + << true; + + QTest::newRow("$$first(): multiple") + << "IN = one two three\nVAR = $$first(IN)" + << "VAR = one" + << "" + << true; + + QTest::newRow("$$first(): bad number of arguments") + << "VAR = $$first(1, 2)" + << "VAR =" + << "##:1: first(var) requires one argument." + << true; + + QTest::newRow("$$last(): empty") + << "IN = \nVAR = $$last(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$last(): one") + << "IN = one\nVAR = $$last(IN)" + << "VAR = one" + << "" + << true; + + QTest::newRow("$$last(): multiple") + << "IN = one two three\nVAR = $$last(IN)" + << "VAR = three" + << "" + << true; + + QTest::newRow("$$last(): bad number of arguments") + << "VAR = $$last(1, 2)" + << "VAR =" + << "##:1: last(var) requires one argument." + << true; + + QTest::newRow("$$size()") + << "IN = one two three\nVAR = $$size(IN)" + << "VAR = 3" + << "" + << true; + + QTest::newRow("$$size(): bad number of arguments") + << "VAR = $$size(1, 2)" + << "VAR =" + << "##:1: size(var) requires one argument." + << true; + + QTest::newRow("$$fromfile(): right var") + << "VAR = $$fromfile(" + qindir + "/fromfile/infile.prx, DEFINES)" + << "VAR = QT_DLL" + << "" + << true; + + QTest::newRow("$$fromfile(): wrong var") + << "VAR = $$fromfile(" + qindir + "/fromfile/infile.prx, INCLUDES)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$fromfile(): bad file") + << "VAR = $$fromfile(" + qindir + "/fromfile/badfile.prx, DEFINES)" + << "VAR =" + << "Project ERROR: fail!" + << true; + + QTest::newRow("$$fromfile(): bad number of arguments") + << "VAR = $$fromfile(1) \\\n$$fromfile(1, 2, 3)" + << "VAR =" + << "##:1: fromfile(file, variable) requires two arguments.\n" + "##:2: fromfile(file, variable) requires two arguments." + << true; + + QTest::newRow("$$eval()") + << "IN = one two three\nVAR = $$eval(IN)" + << "VAR = one two three" + << "" + << true; + + QTest::newRow("$$eval(): bad number of arguments") + << "VAR = $$eval(1, 2)" + << "VAR =" + << "##:1: eval(variable) requires one argument." + << true; + + QTest::newRow("$$list()") + << "VARNAME = $$list(one, two three, 'four five')\nVAR = $$eval($$VARNAME)" + << "VAR = one two three four five" // total nonsense ... + << "" + << true; + + QTest::newRow("$$sprintf()") + << "VAR = $$sprintf(hello %1 %2, you, there)" + << "VAR = 'hello you there'" + << "" + << true; + + QTest::newRow("$$format_number(): simple number format") + << "VAR = $$format_number(13)" + << "VAR = 13" + << "" + << true; + + QTest::newRow("$$format_number(): negative number format") + << "VAR = $$format_number(-13)" + << "VAR = -13" + << "" + << true; + + QTest::newRow("$$format_number(): hex input number format") + << "VAR = $$format_number(13, ibase=16)" + << "VAR = 19" + << "" + << true; + + QTest::newRow("$$format_number(): hex output number format") + << "VAR = $$format_number(13, obase=16)" + << "VAR = d" + << "" + << true; + + QTest::newRow("$$format_number(): right aligned number format") + << "VAR = $$format_number(13, width=5)" + << "VAR = ' 13'" + << "" + << true; + + QTest::newRow("$$format_number(): left aligned number format") + << "VAR = $$format_number(13, width=5 leftalign)" + << "VAR = '13 '" + << "" + << true; + + QTest::newRow("$$format_number(): zero-padded number format") + << "VAR = $$format_number(13, width=5 zeropad)" + << "VAR = 00013" + << "" + << true; + + QTest::newRow("$$format_number(): always signed number format") + << "VAR = $$format_number(13, width=5 alwayssign)" + << "VAR = ' +13'" + << "" + << true; + + QTest::newRow("$$format_number(): zero-padded always signed number format") + << "VAR = $$format_number(13, width=5 alwayssign zeropad)" + << "VAR = +0013" + << "" + << true; + + QTest::newRow("$$format_number(): sign-padded number format") + << "VAR = $$format_number(13, width=5 padsign)" + << "VAR = ' 13'" + << "" + << true; + + QTest::newRow("$$format_number(): zero-padded sign-padded number format") + + << "VAR = $$format_number(13, width=5 padsign zeropad)" + << "VAR = ' 0013'" + << "" + << true; + + QTest::newRow("$$format_number(): bad number of arguments") + << "VAR = $$format_number(13, 1, 2)" + << "VAR =" + << "##:1: format_number(number[, options...]) requires one or two arguments." + << true; + + QTest::newRow("$$format_number(): invalid option") + << "VAR = $$format_number(13, foo=bar)" + << "VAR =" + << "##:1: format_number(): invalid format option foo=bar." + << true; + + QTest::newRow("$$join(): empty") + << "IN = \nVAR = $$join(IN, //)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$join(): multiple") + << "IN = one two three\nVAR = $$join(IN, //)" + << "VAR = one//two//three" + << "" + << true; + + QTest::newRow("$$join(): multiple surrounded") + << "IN = one two three\nVAR = $$join(IN, //, <<, >>)" + << "VAR = <>" + << "" + << true; + + QTest::newRow("$$join(): bad number of arguments") + << "VAR = $$join(1, 2, 3, 4, 5)" + << "VAR =" + << "##:1: join(var, glue, before, after) requires one to four arguments." + << true; + + QTest::newRow("$$split(): default sep") + << "IN = 'one/two three' 'four / five'\nVAR = $$split(IN)" + << "VAR = one/two three four / five" + << "" + << true; + + QTest::newRow("$$split(): specified sep") + << "IN = 'one/two three' 'four / five'\nVAR = $$split(IN, /)" + << "VAR = one 'two three' 'four ' ' five'" + << "" + << true; + + QTest::newRow("$$split(): bad number of arguments") + << "VAR = $$split(1, 2, 3)" + << "VAR =" + << "##:1: split(var, sep) requires one or two arguments." + << true; + + QTest::newRow("$$basename(): empty") + << "IN = \nVAR = $$basename(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$basename(): bare") + << "IN = file\nVAR = $$basename(IN)" + << "VAR = file" + << "" + << true; + + QTest::newRow("$$basename(): relative") + << "IN = path/file\nVAR = $$basename(IN)" + << "VAR = file" + << "" + << true; + + QTest::newRow("$$basename(): absolute") + << "IN = \\\\path\\\\file\nVAR = $$basename(IN)" + << "VAR = file" + << "" + << true; + + QTest::newRow("$$basename(): bad number of arguments") + << "VAR = $$basename(1, 2)" + << "VAR =" + << "##:1: basename(var) requires one argument." + << true; + + QTest::newRow("$$dirname(): empty") + << "IN = \nVAR = $$dirname(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$dirname(): bare") + << "IN = file\nVAR = $$dirname(IN)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$dirname(): relative") + << "IN = path/file\nVAR = $$dirname(IN)" + << "VAR = path" + << "" + << true; + + QTest::newRow("$$dirname(): absolute") + << "IN = \\\\path\\\\file\nVAR = $$dirname(IN)" + << "VAR = \\\\path" + << "" + << true; + + QTest::newRow("$$dirname(): bad number of arguments") + << "VAR = $$dirname(1, 2)" + << "VAR =" + << "##:1: dirname(var) requires one argument." + << true; + + QTest::newRow("$$section(): explicit end") + << "IN = one~two~three~four~five~six\nVAR = $$section(IN, ~, 2, 4)" + << "VAR = three~four~five" + << "" + << true; + + QTest::newRow("$$section(): implicit end") + << "IN = one~two~three~four~five~six\nVAR = $$section(IN, ~, 3)" + << "VAR = four~five~six" + << "" + << true; + + QTest::newRow("$$section(): bad number of arguments") + << "VAR = $$section(1, 2) \\\n$$section(1, 2, 3, 4, 5)" + << "VAR =" + << "##:1: section(var) section(var, sep, begin, end) requires three or four arguments.\n" + "##:2: section(var) section(var, sep, begin, end) requires three or four arguments." + << true; + + QTest::newRow("$$find()") + << "IN = foo bar baz blubb\nVAR = $$find(IN, ^ba)" + << "VAR = bar baz" + << "" + << true; + + QTest::newRow("$$find(): bad number of arguments") + << "VAR = $$find(1) \\\n$$find(1, 2, 3)" + << "VAR =" + << "##:1: find(var, str) requires two arguments.\n" + "##:2: find(var, str) requires two arguments." + << true; + + // FIXME: $$cat() & $$system(): There is no way to generate the newlines + // necessary for testing "multi-line" and "blob" mode adequately. + // Note: these functions have *different* splitting behavior. + + // This gives split_value_list() an exercise + QTest::newRow("$$cat(): default mode") + << "VAR = $$cat(" + qindir + "/cat/file2.txt)" + << "VAR = foo bar baz \"\\\"Hello, \\' world.\\\"\" post \"\\'Hello, \\\" world.\\'\" post \\\\\\\" \\\\\\' \\\\\\\\ \\\\a \\\\ nix \"\\\" \\\"\"" + << "" + << true; + + QTest::newRow("$$cat(): lines mode") + << "VAR = $$cat(" + qindir + "/cat/file1.txt, lines)" + << "VAR = '\"Hello, world.\"' 'foo bar baz'" + << "" + << true; + + QTest::newRow("$$cat(): bad number of arguments") + << "VAR = $$cat(1, 2, 3)" + << "VAR =" + << "##:1: cat(file, singleline=true) requires one or two arguments." + << true; + + QTest::newRow("$$system(): default mode") +#ifdef Q_OS_WIN + << "VAR = $$system('echo Hello, ^\"world.&& echo foo^\" bar baz')" +#else + << "VAR = $$system('echo Hello, \\\\\\\"world. && echo foo\\\\\\\" bar baz')" +#endif + << "VAR = Hello, '\"world. foo\"' bar baz" + << "" + << true; + + QTest::newRow("$$system(): lines mode") +#ifdef Q_OS_WIN + << "VAR = $$system('echo Hello, ^\"world.&& echo foo^\" bar baz', lines)" +#else + << "VAR = $$system('echo Hello, \\\\\\\"world. && echo foo\\\\\\\" bar baz', lines)" +#endif + << "VAR = 'Hello, \"world.' 'foo\" bar baz'" + << "" + << true; + + QTest::newRow("$$system(): bad number of arguments") + << "VAR = $$system(1, 2, 3)" + << "VAR =" + << "##:1: system(execute) requires one or two arguments." + << true; + + QTest::newRow("$$unique()") + << "IN = foo bar foo baz\nVAR = $$unique(IN)" + << "VAR = foo bar baz" + << "" + << true; + + QTest::newRow("$$unique(): bad number of arguments") + << "VAR = $$unique(1, 2)" + << "VAR =" + << "##:1: unique(var) requires one argument." + << true; + + QTest::newRow("$$reverse()") + << "IN = one two three\nVAR = $$reverse(IN)" + << "VAR = three two one" + << "" + << true; + + QTest::newRow("$$reverse(): bad number of arguments") + << "VAR = $$reverse(1, 2)" + << "VAR =" + << "##:1: reverse(var) requires one argument." + << true; + + QTest::newRow("$$quote()") + << "VAR = $$quote(foo bar, 'foo bar')" + << "VAR = 'foo bar' 'foo bar'" + << "" + << true; + + // FIXME: \n and \r go untested, because there is no way to get them into the + // expected result. And if there was one, this function would be unnecessary. + // In other news, the behavior of backslash escaping makes no sense. + QTest::newRow("$$escape_expand()") + << "VAR = $$escape_expand(foo\\\\ttab\\\\\\\\slash\\\\invalid, verbatim)" + << "VAR = 'foo\ttab\\\\\\\\slash\\\\invalid' verbatim" + << "" + << true; + + QTest::newRow("$$upper()") + << "VAR = $$upper(kEwL, STuff)" + << "VAR = KEWL STUFF" + << "" + << true; + + QTest::newRow("$$lower()") + << "VAR = $$lower(kEwL, STuff)" + << "VAR = kewl stuff" + << "" + << true; + + QTest::newRow("$$title()") + << "VAR = $$title(kEwL, STuff)" + << "VAR = Kewl Stuff" + << "" + << true; + + QTest::newRow("$$re_escape()") + << "VAR = $$re_escape(one, hey.*you[funny]+people)" + << "VAR = one hey\\\\.\\\\*you\\\\[funny\\\\]\\\\+people" + << "" + << true; + + QTest::newRow("$$val_escape()") + << "IN = easy \"less easy\" sca$${LITERAL_HASH}ry" + " crazy$$escape_expand(\\\\t\\\\r\\\\n)" + " $$escape_expand(\\\\t)stuff \\'no\\\"way\\\\here\n" + "VAR = $$val_escape(IN)" + << "VAR = easy '\\\"less easy\\\"' sca\\$\\${LITERAL_HASH}ry" + " crazy\\$\\$escape_expand(\\\\\\\\t\\\\\\\\r\\\\\\\\n)" + " \\$\\$escape_expand(\\\\\\\\t)stuff \\\\\\'no\\\\\\\"way\\\\\\\\here" + << "" + << true; + + QTest::newRow("$$val_escape(): bad number of arguments") + << "VAR = $$val_escape(1, 2)" + << "VAR =" + << "##:1: val_escape(var) requires one argument." + << true; + + QTest::newRow("$$files(): non-recursive") + << "VAR = $$files(" + qindir + "/files/file*.txt)" + << "VAR = " + qindir + "/files/file1.txt " + + qindir + "/files/file2.txt" + << "" + << true; + + QTest::newRow("$$files(): recursive") + << "VAR = $$files(" + qindir + "/files/file*.txt, true)" + << "VAR = " + qindir + "/files/file1.txt " + + qindir + "/files/file2.txt " + + qindir + "/files/dir/file1.txt " + + qindir + "/files/dir/file2.txt" + << "" + << true; + + QTest::newRow("$$files(): bad number of arguments") + << "VAR = $$files(1, 2, 3)" + << "VAR =" + << "##:1: files(pattern, recursive=false) requires one or two arguments." + << true; + +#if 0 + // FIXME: no emulated input layer + QTest::newRow("$$prompt()") + << "VAR = $$prompt(que)" + << "VAR = whatever" + << "Project PROMPT: que? " + << true; +#endif + + QTest::newRow("$$replace()") + << "IN = foo 'bar baz'\nVAR = $$replace(IN, \\\\bba, hello)" + << "VAR = foo 'hellor helloz'" + << "" + << true; + + QTest::newRow("$$replace(): bad number of arguments") + << "VAR = $$replace(1, 2) \\\n$$replace(1, 2, 3, 4)" + << "VAR =" + << "##:1: replace(var, before, after) requires three arguments.\n" + "##:2: replace(var, before, after) requires three arguments." + << true; + + QTest::newRow("$$sort_depends()") + << "foo.depends = bar baz\n" + "bar.depends = baz bak duck\n" + "baz.depends = bak\n" + "bak.depends = duck\n" + "VAR = $$sort_depends($$list(baz foo duck bar))" + << "VAR = foo bar baz duck" + << "" + << true; + + QTest::newRow("$$resolve_depends(): basic") + << "foo.depends = bar baz\n" + "bar.depends = baz bak duck\n" + "baz.depends = bak\n" + "bak.depends = duck\n" + "VAR = $$resolve_depends($$list(baz foo duck bar))" + << "VAR = foo bar baz bak duck" + << "" + << true; + + QTest::newRow("$$resolve_depends(): prefix and multiple suffixes") + << "MOD.foo.dep = bar baz\n" + "MOD.bar.dep = baz bak\n" + "MOD.bar.priv_dep = duck\n" + "MOD.baz.dep = bak\n" + "MOD.bak.dep = duck\n" + "VAR = $$resolve_depends($$list(baz foo duck bar), MOD., .dep .priv_dep)" + << "VAR = foo bar baz bak duck" + << "" + << true; + + QTest::newRow("$$resolve_depends(): priorities: b first") + << "MOD.a.depends =\n" + "MOD.b.depends =\n" + "MOD.b.priority = 1\n" + "MOD.c.depends = a b\n" + "VAR = $$resolve_depends($$list(c), MOD.)" + << "VAR = c b a" + << "" + << true; + + QTest::newRow("$$resolve_depends(): priorities: a first") + << "MOD.a.depends =\n" + "MOD.a.priority = 1\n" + "MOD.b.depends =\n" + "MOD.b.priority = 0\n" + "MOD.c.depends = a b\n" + "VAR = $$resolve_depends($$list(c), MOD.)" + << "VAR = c a b" + << "" + << true; + + QTest::newRow("$$resolve_depends(): priorities: custom suffix") + << "MOD.a.depends =\n" + "MOD.a.prrt = 1\n" + "MOD.b.depends =\n" + "MOD.b.prrt = 0\n" + "MOD.c.depends = a b\n" + "VAR = $$resolve_depends($$list(c), MOD., .depends, .prrt)" + << "VAR = c a b" + << "" + << true; + + QTest::newRow("$$resolve_depends(): bad number of arguments") + << "VAR = $$resolve_depends(1, 2, 3, 4, 5)" + << "VAR =" + << "##:1: resolve_depends(var, [prefix, [suffixes, [prio-suffix]]]) requires one to four arguments." + << true; + + QTest::newRow("$$enumerate_vars()") + << "V1 = foo\nV2 = bar\nVAR = $$enumerate_vars()\n" + "count(VAR, 2, >=):contains(VAR, V1):contains(VAR, V2): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("$$shadowed(): bare") + << "VAR = $$shadowed(test.txt)" + << "VAR = " + QMakeEvaluator::quoteValue(ProString(m_outdir + "/test.txt")) + << "" + << true; + + QTest::newRow("$$shadowed(): subdir") + << "VAR = $$shadowed(" + qindir + "/sub/test.txt)" + << "VAR = " + QMakeEvaluator::quoteValue(ProString(m_outdir + "/sub/test.txt")) + << "" + << true; + + QTest::newRow("$$shadowed(): outside source dir") + << "VAR = $$shadowed(/some/random/path)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$shadowed(): bad number of arguments") + << "VAR = $$shadowed(1, 2)" + << "VAR =" + << "##:1: shadowed(path) requires one argument." + << true; + + QTest::newRow("$$absolute_path(): relative file") + << "VAR = $$absolute_path(dir/file.ext)" + << "VAR = " + qindir + "/dir/file.ext" + << "" + << true; + + QTest::newRow("$$absolute_path(): file & path") + << "VAR = $$absolute_path(dir/file.ext, /root/sub)" + << "VAR = /root/sub/dir/file.ext" + << "" + << true; + + QTest::newRow("$$absolute_path(): absolute file & path") + << "VAR = $$absolute_path(/root/sub/dir/file.ext, /other)" + << "VAR = /root/sub/dir/file.ext" + << "" + << true; + + QTest::newRow("$$absolute_path(): empty file & path") + << "VAR = $$absolute_path('', /root/sub)" + << "VAR = /root/sub" + << "" + << true; + + QTest::newRow("$$absolute_path(): bad number of arguments") + << "VAR = $$absolute_path(1, 2, 3)" + << "VAR =" + << "##:1: absolute_path(path[, base]) requires one or two arguments." + << true; + + QTest::newRow("$$relative_path(): relative file") + << "VAR = $$relative_path(dir/file.ext)" + << "VAR = dir/file.ext" + << "" + << true; + + QTest::newRow("$$relative_path(): relative file to empty") + << "VAR = $$relative_path(dir/..)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$relative_path(): absolute file & path") + << "VAR = $$relative_path(/root/sub/dir/file.ext, /root/sub)" + << "VAR = dir/file.ext" + << "" + << true; + + QTest::newRow("$$relative_path(): empty file & path") + << "VAR = $$relative_path('', /root/sub)" + << "VAR =" + << "" + << true; + + QTest::newRow("$$relative_path(): bad number of arguments") + << "VAR = $$relative_path(1, 2, 3)" + << "VAR =" + << "##:1: relative_path(path[, base]) requires one or two arguments." + << true; + + QTest::newRow("$$clean_path()") +#ifdef Q_OS_WIN // This is actually kinda stupid. + << "VAR = $$clean_path(foo//bar\\\\../baz/)" +#else + << "VAR = $$clean_path(foo//bar/../baz/)" +#endif + << "VAR = foo/baz" + << "" + << true; + + QTest::newRow("$$clean_path(): bad number of arguments") + << "VAR = $$clean_path(1, 2)" + << "VAR =" + << "##:1: clean_path(path) requires one argument." + << true; + + QTest::newRow("$$system_path()") + << "VAR = $$system_path(foo/bar\\\\baz)" +#ifdef Q_OS_WIN + << "VAR = foo\\\\bar\\\\baz" +#else + << "VAR = foo/bar/baz" +#endif + << "" + << true; + + QTest::newRow("$$system_path(): bad number of arguments") + << "VAR = $$system_path(1, 2)" + << "VAR =" + << "##:1: system_path(path) requires one argument." + << true; + + // This is is effectively $$system_path() in this test, as we load no specs + QTest::newRow("$$shell_path()") + << "VAR = $$shell_path(foo/bar\\\\baz)" +#ifdef Q_OS_WIN + << "VAR = foo\\\\bar\\\\baz" +#else + << "VAR = foo/bar/baz" +#endif + << "" + << true; + + QTest::newRow("$$shell_path(): bad number of arguments") + << "VAR = $$shell_path(1, 2)" + << "VAR =" + << "##:1: shell_path(path) requires one argument." + << true; + + // The quoteArgs() test exercises this more thoroughly + QTest::newRow("$$system_quote()") + << "IN = \nVAR = $$system_quote(\"some nasty & ugly\\\" path & thing\\\\\")" +#ifdef Q_OS_WIN + << "VAR = \"\\\"some nasty & ugly\\\\\\\" path ^& thing\\\\\\\\^\\\"\"" +#else + << "VAR = \"'some nasty & ugly\\\" path & thing\\\\'\"" +#endif + << "" + << true; + + QTest::newRow("$$system_quote(): bad number of arguments") + << "VAR = $$system_quote(1, 2)" + << "VAR =" + << "##:1: system_quote(arg) requires one argument." + << true; + + // This is is effectively $$system_path() in this test, as we load no specs + QTest::newRow("$$shell_quote()") + << "IN = \nVAR = $$shell_quote(\"some nasty & ugly\\\" path & thing\\\\\")" +#ifdef Q_OS_WIN + << "VAR = \"\\\"some nasty & ugly\\\\\\\" path ^& thing\\\\\\\\^\\\"\"" +#else + << "VAR = \"'some nasty & ugly\\\" path & thing\\\\'\"" +#endif + << "" + << true; + + QTest::newRow("$$shell_quote(): bad number of arguments") + << "VAR = $$shell_quote(1, 2)" + << "VAR =" + << "##:1: shell_quote(arg) requires one argument." + << true; + + QTest::newRow("$$getenv()") + << "VAR = $$getenv(E1)" + << "VAR = 'env var'" + << "" + << true; + + QTest::newRow("$$getenv(): bad number of arguments") + << "VAR = $$getenv(1, 2)" + << "VAR =" + << "##:1: getenv(arg) requires one argument." + << true; +} + +void tst_qmakelib::addTestFunctions(const QString &qindir) +{ + QTest::newRow("defined(): found replace") + << "defineReplace(func) {}\ndefined(func): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(): found test") + << "defineTest(func) {}\ndefined(func): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(): not found") + << "defined(func): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("defined(replace): found") + << "defineReplace(func) {}\ndefined(func, replace): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(replace): not found") + << "defineTest(func) {}\ndefined(func, replace): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("defined(test): found") + << "defineTest(func) {}\ndefined(func, test): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(test): not found") + << "defineReplace(func) {}\ndefined(func, test): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("defined(var): found") + << "VAR = 1\ndefined(VAR, var): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("defined(var): not found") + << "defined(VAR, var): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("defined(): invalid type") + << "defined(VAR, nope): OK = 1" + << "OK = UNDEF" + << "##:1: defined(function, type): unexpected type [nope]." + << true; + + QTest::newRow("defined(): bad number of arguments") + << "defined(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: defined(function, [\"test\"|\"replace\"|\"var\"]) requires one or two arguments." + << true; + + QTest::newRow("export()") + << "defineTest(func) {\n" + "VAR1 += different\nexport(VAR1)\n" + "unset(VAR2)\nexport(VAR2): OK = 1\nexport(OK)\n" + "VAR3 = new var\nexport(VAR3)\n" + "}\n" + "VAR1 = entirely\nVAR2 = set\nfunc()" + << "OK = 1\nVAR1 = entirely different\nVAR2 =\nVAR3 = new var" + << "" + << true; + + QTest::newRow("export(): bad number of arguments") + << "export(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: export(variable) requires one argument." + << true; + + QTest::newRow("infile(): found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("infile(): not found") + << "infile(" + qindir + "/fromfile/infile.prx, INCLUDES): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("infile(plain): found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES, QT_DLL): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("infile(plain): not found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES, NOPE): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("infile(regex): found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES, QT_.*): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("infile(regex): not found") + << "infile(" + qindir + "/fromfile/infile.prx, DEFINES, NO.*): OK = 1" + << "OK = UNDEF" + << "" + << true; + + // The early return is debatable, esp. as it's inconsistent with $$fromfile() + QTest::newRow("infile(): bad file") + << "infile(" + qindir + "/fromfile/badfile.prx, DEFINES): OK = 1\nOKE = 1" + << "OK = UNDEF\nOKE = UNDEF" + << "Project ERROR: fail!" + << false; + + QTest::newRow("infile(): bad number of arguments") + << "infile(1): OK = 1\ninfile(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: infile(file, var, [values]) requires two or three arguments.\n" + "##:2: infile(file, var, [values]) requires two or three arguments." + << true; + + QTest::newRow("requires()") + << "requires(true, false, isEmpty(FOO), !isEmpty(BAR), true|false, true:false)" + << "QMAKE_FAILED_REQUIREMENTS = false !isEmpty(BAR) true:false" + << "" + << true; + + // The sparator semantics are *very* questionable. + // The return value semantics are rather questionable. + QTest::newRow("eval()") + << "eval(FOO = one, two$$escape_expand(\\\\n)BAR = blah$$escape_expand(\\\\n)error(fail)$$escape_expand(\\\\n)BAZ = nope)" + << "FOO = one two\nBAR = blah\nBAZ = UNDEF" + << "Project ERROR: fail" + << true; + + QTest::newRow("if(): true") + << "if(false|true): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("if(): true (space)") + << "if(false| true): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("if(): true (spaces)") + << "if( false | true ): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("if(): false") + << "if(false:true): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("if(): false (space)") + << "if(false: true): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("if(): false (spaces)") + << "if( false : true ): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("if(): bad number of arguments") + << "if(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: if(condition) requires one argument." + << true; + + QTest::newRow("CONFIG(simple): true") + << "CONFIG = debug release\nCONFIG(debug): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("CONFIG(simple): false") + << "CONFIG = debug release\nCONFIG(nope): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("CONFIG(alt): true") + << "CONFIG = debug release\nCONFIG(release, debug|release): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("CONFIG(alt): false (presence)") + << "CONFIG = not here\nCONFIG(debug, debug|release): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("CONFIG(alt): false (order)") + << "CONFIG = debug release\nCONFIG(debug, debug|release): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("CONFIG(): bad number of arguments") + << "CONFIG(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: CONFIG(config) requires one or two arguments." + << true; + + QTest::newRow("contains(simple plain): true") + << "VAR = one two three\ncontains(VAR, two): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("contains(simple plain): false") + << "VAR = one two three\ncontains(VAR, four): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(simple regex): true") + << "VAR = one two three\ncontains(VAR, tw.*): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("contains(simple regex): false") + << "VAR = one two three\ncontains(VAR, fo.*): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(alt plain): true") + << "VAR = one two three\ncontains(VAR, three, two|three): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("contains(alt plain): false (presence)") + << "VAR = one four five\ncontains(VAR, three, two|three): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(alt plain): false (order)") + << "VAR = one two three\ncontains(VAR, two, two|three): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(alt regex): true") + << "VAR = one two three\ncontains(VAR, th.*, two|three): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("contains(alt regex): false (presence)") + << "VAR = one four five\ncontains(VAR, th.*, two|three): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(alt regex): false (order)") + << "VAR = one two three\ncontains(VAR, tw.*, two|three): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("contains(): bad number of arguments") + << "contains(1): OK = 1\ncontains(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: contains(var, val) requires two or three arguments.\n" + "##:2: contains(var, val) requires two or three arguments." + << true; + + QTest::newRow("count(): true") + << "VAR = one two three\ncount(VAR, 3): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("count(): false") + << "VAR = one two three\ncount(VAR, 4): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("count(operators): true") + << "VAR = one two three\n" + "count(VAR, 3, equals): OKE1 = 1\n" + "count(VAR, 3, isEqual): OKE2 = 1\n" + "count(VAR, 3, =): OKE3 = 1\n" + "count(VAR, 3, ==): OKE4 = 1\n" + "count(VAR, 2, greaterThan): OKG1 = 1\n" + "count(VAR, 2, >): OKG2 = 1\n" + "count(VAR, 2, >=): OKGE = 1\n" + "count(VAR, 4, lessThan): OKL1 = 1\n" + "count(VAR, 4, <): OKL2 = 1\n" + "count(VAR, 4, <=): OKLE = 1\n" + << "OKE1 = 1\nOKE2 = 1\nOKE3 = 1\nOKE4 = 1\n" + "OKG1 = 1\nOKG2 = 1\nOKGE = 1\n" + "OKL1 = 1\nOKL2 = 1\nOKLE = 1" + << "" + << true; + + QTest::newRow("count(operators): false") + << "VAR = one two three\n" + "count(VAR, 4, equals): OKE1 = 1\n" + "count(VAR, 4, isEqual): OKE2 = 1\n" + "count(VAR, 4, =): OKE3 = 1\n" + "count(VAR, 4, ==): OKE4 = 1\n" + "count(VAR, 3, greaterThan): OKG1 = 1\n" + "count(VAR, 3, >): OKG2 = 1\n" + "count(VAR, 4, >=): OKGE = 1\n" + "count(VAR, 3, lessThan): OKL1 = 1\n" + "count(VAR, 3, <): OKL2 = 1\n" + "count(VAR, 2, <=): OKLE = 1\n" + << "OKE1 = UNDEF\nOKE2 = UNDEF\nOKE3 = UNDEF\nOKE4 = UNDEF\n" + "OKG1 = UNDEF\nOKG2 = UNDEF\nOKGE = UNDEF\n" + "OKL1 = UNDEF\nOKL2 = UNDEF\nOKLE = UNDEF" + << "" + << true; + + QTest::newRow("count(): bad operator") + << "VAR = one two three\ncount(VAR, 2, !!!): OK = 1" + << "OK = UNDEF" + << "##:2: Unexpected modifier to count(!!!)." + << true; + + QTest::newRow("count(): bad number of arguments") + << "count(1): OK = 1\ncount(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: count(var, count, op=\"equals\") requires two or three arguments.\n" + "##:2: count(var, count, op=\"equals\") requires two or three arguments." + << true; + + QTest::newRow("greaterThan(int): true") + << "VAR = 20\ngreaterThan(VAR, 3): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("greaterThan(int): false") + << "VAR = 3\ngreaterThan(VAR, 20): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("greaterThan(string): true") + << "VAR = foo 3\ngreaterThan(VAR, foo 20): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("greaterThan(string): false") + << "VAR = foo 20\ngreaterThan(VAR, foo 3): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("greaterThan(): bad number of arguments") + << "greaterThan(1): OK = 1\ngreaterThan(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: greaterThan(variable, value) requires two arguments.\n" + "##:2: greaterThan(variable, value) requires two arguments." + << true; + + QTest::newRow("lessThan(int): true") + << "VAR = 3\nlessThan(VAR, 20): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("lessThan(int): false") + << "VAR = 20\nlessThan(VAR, 3): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("lessThan(string): true") + << "VAR = foo 20\nlessThan(VAR, foo 3): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("lessThan(string): false") + << "VAR = foo 3\nlessThan(VAR, foo 20): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("lessThan(): bad number of arguments") + << "lessThan(1): OK = 1\nlessThan(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: lessThan(variable, value) requires two arguments.\n" + "##:2: lessThan(variable, value) requires two arguments." + << true; + + QTest::newRow("equals(): true") + << "VAR = foo\nequals(VAR, foo): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("equals(): false") + << "VAR = foo\nequals(VAR, bar): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("equals(): bad number of arguments") + << "equals(1): OK = 1\nequals(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: equals(variable, value) requires two arguments.\n" + "##:2: equals(variable, value) requires two arguments." + << true; + + // That's just an alias, so don't test much. + QTest::newRow("isEqual(): true") + << "VAR = foo\nisEqual(VAR, foo): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("clear(): top-level") + << "VAR = there\nclear(VAR): OK = 1" + << "OK = 1\nVAR =" + << "" + << true; + + QTest::newRow("clear(): scoped") + << "defineTest(func) {\n" + "clear(VAR): OK = 1\nexport(OK)\n" + "equals(VAR, \"\"): OKE = 1\nexport(OKE)\n" + "}\n" + "VAR = there\nfunc()" + << "OK = 1\nOKE = 1" + << "" + << true; + + QTest::newRow("clear(): absent") + << "clear(VAR): OK = 1" + << "OK = UNDEF\nVAR = UNDEF" + << "" + << true; + + QTest::newRow("clear(): bad number of arguments") + << "clear(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: clear(variable) requires one argument." + << true; + + QTest::newRow("unset(): top-level") + << "VAR = there\nunset(VAR): OK = 1" + << "OK = 1\nVAR = UNDEF" + << "" + << true; + + QTest::newRow("unset(): scoped") + << "defineTest(func) {\n" + "unset(VAR): OK = 1\nexport(OK)\n" + "!defined(VAR, var): OKE = 1\nexport(OKE)\n" + "}\n" + "VAR = there\nfunc()" + << "OK = 1\nOKE = 1" + << "" + << true; + + QTest::newRow("unset(): absent") + << "unset(VAR): OK = 1" + << "OK = UNDEF\nVAR = UNDEF" + << "" + << true; + + QTest::newRow("unset(): bad number of arguments") + << "unset(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: unset(variable) requires one argument." + << true; + + // This function does not follow the established naming pattern. + QTest::newRow("parseJson()") + << "jsontext = \\\n" + " \"{\"\\\n" + " \" \\\"array\\\" : [\\\"arrayItem1\\\", \\\"arrayItem2\\\", \\\"arrayItem3\\\"],\"\\\n" + " \" \\\"object\\\" : { \\\"key1\\\" : \\\"objectValue1\\\", \\\"key2\\\" : \\\"objectValue2\\\" },\"\\\n" + " \" \\\"string\\\" : \\\"test string\\\",\"\\\n" + " \" \\\"number\\\" : 999,\"\\\n" + " \" \\\"true\\\" : true,\"\\\n" + " \" \\\"false\\\" :false,\"\"\\\n" + " \" \\\"null\\\" : null\"\"\\\n" + " \"}\"\n" + "parseJson(jsontext, json): OK = 1" + << "OK = 1\n" + "json._KEYS_ = array false null number object string true\n" + // array + "json.array._KEYS_ = 0 1 2\n" + "json.array.0 = arrayItem1\n" + "json.array.1 = arrayItem2\n" + "json.array.2 = arrayItem3\n" + // object + "json.object._KEYS_ = key1 key2\n" + "json.object.key1 = objectValue1\n" + "json.object.key1 = objectValue1\n" + // value types + "json.string = 'test string'\n" + "json.number = 999\n" + "json.true = true\n" + "json.false = false\n" + "json.null = UNDEF" + << "" + << true; + + QTest::newRow("parseJson(): bad input") + << "jsontext = not good\n" + "parseJson(jsontext, json): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("parseJson(): bad number of arguments") + << "parseJson(1): OK = 1\nparseJson(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: parseJson(variable, into) requires two arguments.\n" + "##:2: parseJson(variable, into) requires two arguments." + << true; + + QTest::newRow("include()") + << "include(include/inc.pri): OK = 1\nfunc()" + << "OK = 1\nVAR = val\n.VAR = nope" + << "Project MESSAGE: say hi!" + << true; + + QTest::newRow("include(): fail") + << "include(include/nope.pri): OK = 1" + << "OK = UNDEF" + << "Cannot read " + m_indir + "/include/nope.pri: No such file or directory" + << true; + + QTest::newRow("include(): silent fail") + << "include(include/nope.pri, , true): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("include(into)") + << "SUB.MISS = 1\ninclude(include/inc.pri, SUB): OK = 1" + << "OK = 1\nSUB.VAR = val\nSUB..VAR = UNDEF\nSUB.MISS = UNDEF\n" + // As a side effect, we test some things that need full project setup + "SUB.MATCH = 1\nSUB.QMAKESPEC = " + qindir + "/mkspecs/fake-g++" + << "" + << true; + + QTest::newRow("include(): bad number of arguments") + << "include(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: include(file, [into, [silent]]) requires one, two or three arguments." + << true; + + QTest::newRow("load()") + << "load(testfeat): OK = 1" + << "OK = 1\nVAR = foo bar" + << "" + << true; + + QTest::newRow("load(): fail") + << "load(no_such_feature): OK = 1" + << "OK = UNDEF" + << "##:1: Cannot find feature no_such_feature" + << true; + + QTest::newRow("load(): silent fail") + << "load(no_such_feature, true): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("load(): bad number of arguments") + << "load(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: load(feature) requires one or two arguments." + << true; + + // We don't test debug() and log(), because they print directly to stderr. + + QTest::newRow("message()") + << "message('Hello, World!'): OK = 1\nOKE = 1" + << "OK = 1\nOKE = 1" + << "Project MESSAGE: Hello, World!" + << true; + + // Don't test that for warning() and error(), as it's the same code path. + QTest::newRow("message(): bad number of arguments") + << "message(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: message(message) requires one argument." + << true; + + QTest::newRow("warning()") + << "warning('World, be warned!'): OK = 1\nOKE = 1" + << "OK = 1\nOKE = 1" + << "Project WARNING: World, be warned!" + << true; + + QTest::newRow("error()") + << "error('World, you FAIL!'): OK = 1\nOKE = 1" + << "OK = UNDEF\nOKE = UNDEF" + << "Project ERROR: World, you FAIL!" + << false; + + QTest::newRow("system()") + << "system('" +#ifdef Q_OS_WIN + "cd" +#else + "pwd" +#endif + "> '" + QMakeEvaluator::quoteValue(ProString(QDir::toNativeSeparators( + m_outdir + "/system_out.txt"))) + "): OK = 1\n" + "DIR = $$cat(" + QMakeEvaluator::quoteValue(ProString( + m_outdir + "/system_out.txt")) + ")" + << "OK = 1\nDIR = " + QMakeEvaluator::quoteValue(ProString(QDir::toNativeSeparators(m_indir))) + << "" + << true; + + QTest::newRow("system(): fail") +#ifdef Q_OS_WIN + << "system(no_such_cmd 2> NUL): OK = 1" +#else + << "system(no_such_cmd 2> /dev/null): OK = 1" +#endif + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("system(): bad number of arguments") + << "system(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: system(exec) requires one argument." + << true; + + QTest::newRow("isEmpty(): true (empty)") + << "VAR =\nisEmpty(VAR): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("isEmpty(): true (undef)") + << "isEmpty(VAR): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("isEmpty(): false") + << "VAR = val\nisEmpty(VAR): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("isEmpty(): bad number of arguments") + << "isEmpty(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: isEmpty(var) requires one argument." + << true; + + QTest::newRow("exists(plain): true") + << "exists(files/file1.txt): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("exists(plain): false") + << "exists(files/not_there.txt): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("exists(wildcard): true") + << "exists(files/fil*.txt): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("exists(wildcard): false") + << "exists(files/not_th*.txt): OK = 1" + << "OK = UNDEF" + << "" + << true; + + QTest::newRow("exists(): bad number of arguments") + << "exists(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: exists(file) requires one argument." + << true; + + QString wpath = QMakeEvaluator::quoteValue(ProString(m_outdir + "/outdir/written.txt")); + QTest::newRow("write_file(): create") + << "VAR = 'this is text' 'yet again'\n" + "write_file(" + wpath + ", VAR): OK = 1\n" + "OUT = $$cat(" + wpath + ", lines)" + << "OK = 1\nOUT = 'this is text' 'yet again'" + << "" + << true; + + QTest::newRow("write_file(): truncate") + << "VAR = 'other content'\n" + "write_file(" + wpath + ", VAR): OK = 1\n" + "OUT = $$cat(" + wpath + ", lines)" + << "OK = 1\nOUT = 'other content'" + << "" + << true; + + QTest::newRow("write_file(): append") + << "VAR = 'one more line'\n" + "write_file(" + wpath + ", VAR, append): OK = 1\n" + "OUT = $$cat(" + wpath + ", lines)" + << "OK = 1\nOUT = 'other content' 'one more line'" + << "" + << true; + + QString vpath = QMakeEvaluator::quoteValue(ProString(m_outdir)); + QTest::newRow("write_file(): fail") + << "write_file(" + vpath + "): OK = 1" + << "OK = UNDEF" +#ifdef Q_OS_WIN + << "##:1: Cannot write file " + QDir::toNativeSeparators(m_outdir) + ": Access is denied." +#else + << "##:1: Cannot write file " + m_outdir + ": Is a directory" +#endif + << true; + + QTest::newRow("write_file(): bad number of arguments") + << "write_file(1, 2, 3, 4): OK = 1" + << "OK = UNDEF" + << "##:1: write_file(name, [content var, [append]]) requires one to three arguments." + << true; + + // FIXME: This doesn't test whether it actually works. + QTest::newRow("touch()") + << "touch(" + wpath + ", files/other.txt): OK = 1" + << "OK = 1" + << "" + << true; + + QTest::newRow("touch(): missing target") + << "touch(/does/not/exist, files/other.txt): OK = 1" + << "OK = UNDEF" +#ifdef Q_OS_WIN + << "##:1: Cannot open /does/not/exist: The system cannot find the path specified." +#else + << "##:1: Cannot touch /does/not/exist: No such file or directory." +#endif + << true; + + QTest::newRow("touch(): missing reference") + << "touch(" + wpath + ", /does/not/exist): OK = 1" + << "OK = UNDEF" +#ifdef Q_OS_WIN + << "##:1: Cannot open reference file /does/not/exist: The system cannot find the path specified." +#else + << "##:1: Cannot stat() reference file /does/not/exist: No such file or directory." +#endif + << true; + + QTest::newRow("touch(): bad number of arguments") + << "touch(1): OK = 1\ntouch(1, 2, 3): OK = 1" + << "OK = UNDEF" + << "##:1: touch(file, reffile) requires two arguments.\n" + "##:2: touch(file, reffile) requires two arguments." + << true; + + QString apath = QMakeEvaluator::quoteValue(ProString(m_outdir + "/a/path")); + QTest::newRow("mkpath()") + << "mkpath(" + apath + "): OK = 1\n" + "exists(" + apath + "): OKE = 1" + << "OK = 1\nOKE = 1" + << "" + << true; + + QString bpath = QMakeEvaluator::quoteValue(ProString(m_outdir + "/fail_me")); + QTest::newRow("mkpath(): fail") + << "write_file(" + bpath + ")|error(FAIL)\n" + "mkpath(" + bpath + "): OK = 1" + << "OK = UNDEF" + << "##:2: Cannot create directory " + QDir::toNativeSeparators(m_outdir + "/fail_me") + '.' + << true; + + QTest::newRow("mkpath(): bad number of arguments") + << "mkpath(1, 2): OK = 1" + << "OK = UNDEF" + << "##:1: mkpath(file) requires one argument." + << true; + +#if 0 + // FIXME ... insanity lies ahead + QTest::newRow("cache()") + << "" + << "" + << "" + << true; +#endif +} + +void tst_qmakelib::proEval_data() +{ + QTest::addColumn("in"); + QTest::addColumn("out"); + QTest::addColumn("msgs"); + QTest::addColumn("ok"); + + QTest::newRow("empty") + << "" + << "VAR = UNDEF" + << "" + << true; + + addAssignments(); + addExpansions(); // Variable, etc. expansions on RHS + addControlStructs(); // Conditions, loops, custom functions + + QString qindir = QMakeEvaluator::quoteValue(ProString(m_indir)); + addReplaceFunctions(qindir); // Built-in replace functions + addTestFunctions(qindir); // Built-in test functions + + // Some compound tests that verify compatibility with odd Qt 4 edge cases + + QTest::newRow("empty (leading)") + << "defineTest(myMsg) { message(\"$$1\") }\n" + "XMPL = /this/is/a/test\n" + "message(split: $$split(XMPL, /))\n" + "message(split joined:$$split(XMPL, /))\n" + "message(\"split quoted: $$split(XMPL, /)\")\n" + "myMsg(my split: $$split(XMPL, /) :post)\n" + "myMsg(my split joined:$$split(XMPL, /):post)\n" + "myMsg(\"my split quoted: $$split(XMPL, /) post\")\n" + "OUT = word $$split(XMPL, /) done\n" + "message(\"assign split separate: $$OUT\")\n" + "OUT = word:$$split(XMPL, /):done\n" + "message(\"assign split joined: $$OUT\")\n" + "OUT = \"word $$split(XMPL, /) done\"\n" + "message(\"assign split quoted: $$OUT\")\n" + << "" + << "Project MESSAGE: split: this is a test\n" + "Project MESSAGE: split joined: this is a test\n" + "Project MESSAGE: split quoted: this is a test\n" + "Project MESSAGE: my split: this is a test :post\n" + "Project MESSAGE: my split joined: this is a test:post\n" + "Project MESSAGE: my split quoted: this is a test post\n" + "Project MESSAGE: assign split separate: word this is a test done\n" + "Project MESSAGE: assign split joined: word: this is a test:done\n" + "Project MESSAGE: assign split quoted: word this is a test done" + << true; + + QTest::newRow("empty (multiple)") + << "defineTest(myMsg) { message(\"$$1\") }\n" + "XMPL = //this///is/a/////test\n" + "message(split: $$split(XMPL, /) :post)\n" + "message(split joined:$$split(XMPL, /):post)\n" + "message(\"split quoted: $$split(XMPL, /) post\")\n" + "myMsg(my split: $$split(XMPL, /) :post)\n" + "myMsg(my split joined:$$split(XMPL, /):post)\n" + "myMsg(\"my split quoted: $$split(XMPL, /) post\")\n" + "OUT = word $$split(XMPL, /) done\n" + "message(\"assign split separate: $$OUT\")\n" + "OUT = word:$$split(XMPL, /):done\n" + "message(\"assign split joined: $$OUT\")\n" + "OUT = \"word $$split(XMPL, /) done\"\n" + "message(\"assign split quoted: $$OUT\")\n" + << "" + << "Project MESSAGE: split: this is a test :post\n" + "Project MESSAGE: split joined: this is a test:post\n" + "Project MESSAGE: split quoted: this is a test post\n" + "Project MESSAGE: my split: this is a test :post\n" + "Project MESSAGE: my split joined: this is a test:post\n" + "Project MESSAGE: my split quoted: this is a test post\n" + "Project MESSAGE: assign split separate: word this is a test done\n" + "Project MESSAGE: assign split joined: word: this is a test:done\n" + "Project MESSAGE: assign split quoted: word this is a test done" + << true; +} + +static QString formatValue(const ProStringList &vals) +{ + QString ret; + + foreach (const ProString &str, vals) { + ret += QLatin1Char(' '); + ret += QMakeEvaluator::quoteValue(str); + } + return ret; +} + +static void skipNoise(const ushort *&tokPtr) +{ + forever { + ushort tok = *tokPtr; + if (tok != TokLine) + break; + tokPtr += 2; + } +} + +static bool compareState(QMakeEvaluator *eval, ProFile *out) +{ + bool ret = true; + const ushort *tokPtr = out->tokPtr(); + forever { + skipNoise(tokPtr); + ushort tok = *tokPtr++; + if (!tok) + break; + if (tok != TokHashLiteral) { + qWarning("Expected output is malformed: not variable%s", + qPrintable(QMakeParser::formatProBlock(out->items()))); + return false; + } + const ProKey &var = out->getHashStr(tokPtr); + tok = *tokPtr++; + if (tok != TokAssign) { + qWarning("Expected output is malformed: not assignment%s", + qPrintable(QMakeParser::formatProBlock(out->items()))); + return false; + } + ProStringList value; + value.reserve(*tokPtr++); + forever { + skipNoise(tokPtr); + tok = *tokPtr++; + if (tok == TokValueTerminator) + break; + if (tok != (TokLiteral | TokNewStr)) { + qWarning("Expected output is malformed: not literal%s", + qPrintable(QMakeParser::formatProBlock(out->items()))); + return false; + } + value << out->getStr(tokPtr); + } + ProValueMap::Iterator it; + ProValueMap *vmap = eval->findValues(var, &it); + if (value.length() == 1 && value.at(0) == "UNDEF") { + if (vmap) { + qWarning("Value of %s is incorrect.\n Actual:%s\nExpected: ", + qPrintable(var.toQString()), + qPrintable(formatValue(*it))); + ret = false; + } + } else { + if (!vmap) { + qWarning("Value of %s is incorrect.\n Actual: \nExpected:%s", + qPrintable(var.toQString()), + qPrintable(formatValue(value))); + ret = false; + } else if (*it != value) { + qWarning("Value of %s is incorrect.\n Actual:%s\nExpected:%s", + qPrintable(var.toQString()), + qPrintable(formatValue(*it)), qPrintable(formatValue(value))); + ret = false; + } + } + } + return ret; +} + +void tst_qmakelib::proEval() +{ + QFETCH(QString, in); + QFETCH(QString, out); + QFETCH(QString, msgs); + QFETCH(bool, ok); + + QString infile = m_indir + "/test.pro"; + bool verified = true; + QMakeTestHandler handler; + handler.setExpectedMessages(msgs.replace("##:", infile + ':').split('\n', QString::SkipEmptyParts)); + QMakeVfs vfs; + QMakeParser parser(0, &vfs, &handler); + QMakeGlobals globals; + globals.do_cache = false; + globals.xqmakespec = "fake-g++"; + globals.environment = m_env; + globals.setProperties(m_prop); + globals.setDirectories(m_indir, m_outdir); + ProFile *outPro = parser.parsedProBlock(out, "out", 1, QMakeParser::FullGrammar); + if (!outPro->isOk()) { + qWarning("Expected output is malformed"); + verified = false; + } + ProFile *pro = parser.parsedProBlock(in, infile, 1, QMakeParser::FullGrammar); + QMakeEvaluator visitor(&globals, &parser, &vfs, &handler); + visitor.setOutputDir(m_outdir); +#ifdef Q_OS_WIN + visitor.m_dirSep = ProString("\\"); +#else + visitor.m_dirSep = ProString("/"); +#endif + QMakeEvaluator::VisitReturn ret + = visitor.visitProFile(pro, QMakeHandler::EvalAuxFile, QMakeEvaluator::LoadProOnly); + if (handler.printedMessages()) { + qWarning("Got unexpected message(s)"); + verified = false; + } + QStringList missingMsgs = handler.expectedMessages(); + if (!missingMsgs.isEmpty()) { + foreach (const QString &msg, missingMsgs) + qWarning("Missing message: %s", qPrintable(msg)); + verified = false; + } + if ((ret == QMakeEvaluator::ReturnTrue) != ok) { + static const char * const lbl[] = { "failure", "success" }; + qWarning("Expected %s, got %s", lbl[int(ok)], lbl[1 - int(ok)]); + verified = false; + } + if (!compareState(&visitor, outPro)) + verified = false; + pro->deref(); + outPro->deref(); + QVERIFY(verified); +} diff --git a/tests/auto/tools/qmakelib/parsertest.cpp b/tests/auto/tools/qmakelib/parsertest.cpp new file mode 100644 index 0000000000..a7b7431a98 --- /dev/null +++ b/tests/auto/tools/qmakelib/parsertest.cpp @@ -0,0 +1,1987 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tst_qmakelib.h" + +#include +#include +#include + +class TokenStream +{ +public: + TokenStream() {} + QString toString() const { return ts; } + + TokenStream &operator<<(ushort n) { ts += QChar(n); return *this; } + TokenStream &operator<<(uint n) { ts += QChar(n & 0xffff); ts += QChar(n >> 16); return *this; } + TokenStream &operator<<(const QStringRef &s) { ts += s; return *this; } + TokenStream &operator<<(const ProString &s) { return *this << ushort(s.length()) << s.toQStringRef(); } + TokenStream &operator<<(const ProKey &s) { return *this << s.hash() << s.toString(); } + +private: + QString ts; +}; + +#define TS(s) (TokenStream() s).toString() +#define H(n) ushort(n) +#define I(n) uint(n) +#define S(s) ProString(QString::fromWCharArray(s)) +#define HS(s) ProKey(QString::fromWCharArray(s)) + +QT_WARNING_PUSH +QT_WARNING_DISABLE_MSVC(4003) // "not enough actual parameters for macro TS()" + +void tst_qmakelib::addParseOperators() +{ + QTest::newRow("assign none") + << "VAR =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("append none") + << "VAR +=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAppend) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("unique append none") + << "VAR *=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAppendUnique) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("remove none") + << "VAR -=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokRemove) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("replace empty") + << "VAR ~=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokReplace) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("assignment without variable") + << "=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokAssign) << H(0) + /* 4 */ << H(TokValueTerminator)) + << "in:1: Assignment needs exactly one word on the left hand side." + << false; + + QTest::newRow("assignment with multiple variables") + << "VAR VAR =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokAssign) << H(0) + /* 4 */ << H(TokValueTerminator)) + << "in:1: Assignment needs exactly one word on the left hand side." + << false; +} + +void tst_qmakelib::addParseValues() +{ +#define ASSIGN_VAR(h) \ + H(TokLine) << H(1) \ + << H(TokHashLiteral) << HS(L"VAR") \ + << H(TokAssign) << H(h) + + QTest::newRow("one literal") + << "VAR = val" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val") + /* 16 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("one literal (squeezed)") + << "VAR=val" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val") + /* 16 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("many literals") + << "VAR = foo barbaz bak hello" + << TS( + /* 0 */ << ASSIGN_VAR(4) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak") + /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello") + /* 36 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("many literals (tab-separated") + << "VAR\t=\tfoo\tbarbaz\tbak\thello" + << TS( + /* 0 */ << ASSIGN_VAR(4) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak") + /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello") + /* 36 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("one quoted literal") + << "VAR = \"val ue\"" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue") + /* 19 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("quoted literal with missing quote") + << "VAR = val \"ue" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(0) + /* 11 */ << H(TokValueTerminator)) + << "in:1: Missing closing \" quote" + << false; + + QTest::newRow("many quoted literals") + << "VAR = \"foo\" barbaz 'bak hello' \"\"" + << TS( + /* 0 */ << ASSIGN_VAR(3) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak hello") + /* 35 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("many quoted literals (with tabs)") + << "VAR\t=\t\"foo\"\tbarbaz\t'bak\thello'" + << TS( + /* 0 */ << ASSIGN_VAR(3) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak\thello") + /* 35 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("quoted and unquoted spaces") + << " VAR = \"val ue \" " + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue ") + /* 22 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("funny literals") + << "VAR = foo:bar|!baz(blam!, ${foo})" + << TS( + /* 0 */ << ASSIGN_VAR(2) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo:bar|!baz(blam!,") + /* 32 */ << H(TokLiteral | TokNewStr) << S(L"${foo})") + /* 41 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("literals with escapes") + << "VAR = \\{hi\\} \\[ho\\] \\)uh\\( \"\\\\oh\\$\"\\' \\$\\${FOO}" + << TS( + /* 0 */ << ASSIGN_VAR(5) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{hi}") + /* 17 */ << H(TokLiteral | TokNewStr) << S(L"[ho]") + /* 23 */ << H(TokLiteral | TokNewStr) << S(L")uh(") + /* 29 */ << H(TokLiteral | TokNewStr) << S(L"\\oh$'") + /* 36 */ << H(TokLiteral | TokNewStr) << S(L"$${FOO}") + /* 45 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("magic variables") + << "VAR = $$LITERAL_HASH $$LITERAL_DOLLAR $$LITERAL_WHITESPACE $$_FILE_ $$_LINE_" + << TS( + /* 0 */ << ASSIGN_VAR(5) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"#") + /* 14 */ << H(TokLiteral | TokNewStr) << S(L"$") + /* 17 */ << H(TokLiteral | TokNewStr) << S(L"\t") + /* 20 */ << H(TokLiteral | TokNewStr) << S(L"in") + /* 24 */ << H(TokLiteral | TokNewStr) << S(L"1") + /* 27 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("continuations and comments") + << "VAR = foo \\\n bar\n \n" + "GAR = foo \\ # comment\n bar \\\n # comment\n baz \\\n" + "\"quoted \\ #comment\n escape\" \\\n right\\\n after \\\n gorilla!\n \n\n" + "MOO = \\\n kuh # comment\nLOO =\n\n" + "FOO = bar \\\n# comment\n baz \\\n \n# comment\n" + "GAZ=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(2) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 21 */ << H(TokValueTerminator) + /* 22 */ << H(TokLine) << H(4) + /* 24 */ << H(TokHashLiteral) << HS(L"GAR") + /* 31 */ << H(TokAssign) << H(7) + /* 33 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 38 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 43 */ << H(TokLiteral | TokNewStr) << S(L"baz") + /* 48 */ << H(TokLiteral | TokNewStr) << S(L"quoted escape") + /* 64 */ << H(TokLiteral | TokNewStr) << S(L"right") + /* 71 */ << H(TokLiteral | TokNewStr) << S(L"after") + /* 78 */ << H(TokLiteral | TokNewStr) << S(L"gorilla!") + /* 88 */ << H(TokValueTerminator) + /* 89 */ << H(TokLine) << H(15) + /* 91 */ << H(TokHashLiteral) << HS(L"MOO") + /* 98 */ << H(TokAssign) << H(0) + /* 100 */ << H(TokLiteral | TokNewStr) << S(L"kuh") + /* 105 */ << H(TokValueTerminator) + /* 106 */ << H(TokLine) << H(17) + /* 108 */ << H(TokHashLiteral) << HS(L"LOO") + /* 115 */ << H(TokAssign) << H(0) + /* 117 */ << H(TokValueTerminator) + /* 118 */ << H(TokLine) << H(19) + /* 120 */ << H(TokHashLiteral) << HS(L"FOO") + /* 127 */ << H(TokAssign) << H(2) + /* 129 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 134 */ << H(TokLiteral | TokNewStr) << S(L"baz") + /* 139 */ << H(TokValueTerminator) + /* 140 */ << H(TokLine) << H(24) + /* 142 */ << H(TokHashLiteral) << HS(L"GAZ") + /* 149 */ << H(TokAssign) << H(0) + /* 151 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("accidental continuation") + << "VAR0 = \\\n this \\\n is \\\n ok\n" + "VAR1 = \\\n this \\\n is=still \\\n ok\n" + "VAR2 = \\\n this \\\n is \\\n" + "VAR3 = \\\n not ok\n" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR0") + /* 10 */ << H(TokAssign) << H(3) + /* 12 */ << H(TokLiteral | TokNewStr) << S(L"this") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"is") + /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ok") + /* 26 */ << H(TokValueTerminator) + /* 27 */ << H(TokLine) << H(5) + /* 29 */ << H(TokHashLiteral) << HS(L"VAR1") + /* 37 */ << H(TokAssign) << H(3) + /* 39 */ << H(TokLiteral | TokNewStr) << S(L"this") + /* 45 */ << H(TokLiteral | TokNewStr) << S(L"is=still") + /* 55 */ << H(TokLiteral | TokNewStr) << S(L"ok") + /* 59 */ << H(TokValueTerminator) + /* 60 */ << H(TokLine) << H(9) + /* 62 */ << H(TokHashLiteral) << HS(L"VAR2") + /* 70 */ << H(TokAssign) << H(6) + /* 72 */ << H(TokLiteral | TokNewStr) << S(L"this") + /* 78 */ << H(TokLiteral | TokNewStr) << S(L"is") + /* 82 */ << H(TokLiteral | TokNewStr) << S(L"VAR3") + /* 88 */ << H(TokLiteral | TokNewStr) << S(L"=") + /* 91 */ << H(TokLiteral | TokNewStr) << S(L"not") + /* 96 */ << H(TokLiteral | TokNewStr) << S(L"ok") + /* 100 */ << H(TokValueTerminator)) + << "WARNING: in:12: Possible accidental line continuation" + << true; + + QTest::newRow("plain variable expansion") + << "VAR = $$bar" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("braced variable expansion") + << "VAR = $${foo/bar}" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"foo/bar") + /* 22 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("bogus variable expansion") + << "VAR = $$ " + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"") + /* 15 */ << H(TokValueTerminator)) + << "WARNING: in:1: Missing name in expansion" + << true; + + QTest::newRow("bogus braced variable expansion") + << "VAR = $${}" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"") + /* 15 */ << H(TokValueTerminator)) + << "WARNING: in:1: Missing name in expansion" + << true; + + QTest::newRow("unterminated braced variable expansion") + << "VAR = $${FOO" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO") + /* 18 */ << H(TokValueTerminator)) + << "in:1: Missing } terminator [found end-of-line]" + << false; + + QTest::newRow("invalid identifier in braced variable expansion") + << "VAR = $${FOO/BAR+BAZ}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO/BAR") + /* 22 */ << H(TokLiteral) << S(L"+BAZ") + /* 28 */ << H(TokValueTerminator)) + << "in:1: Missing } terminator [found +]" + << false; + + QTest::newRow("property expansion") + << "VAR = $$[bar]" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokProperty | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("environment expansion") + << "VAR = $$(bar)" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokEnvVar | TokNewStr) << S(L"bar") + /* 16 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("plain function call") + << "VAR = $$bar()" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokFuncTerminator) + /* 19 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("braced function call") + << "VAR = $${bar()}" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokFuncTerminator) + /* 19 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("function call with one argument") + << "VAR = $$bar(blubb)" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 25 */ << H(TokFuncTerminator) + /* 26 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("function call with multiple arguments") + << "VAR = $$bar( blubb blubb, hey ,$$you)" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 25 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 32 */ << H(TokArgSeparator) + /* 33 */ << H(TokLiteral | TokNewStr) << S(L"hey") + /* 38 */ << H(TokArgSeparator) + /* 39 */ << H(TokVariable | TokNewStr) << HS(L"you") + /* 46 */ << H(TokFuncTerminator) + /* 47 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("nested function call") + << "VAR = $$foo(yo, $$bar(blubb))" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"foo") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"yo") + /* 22 */ << H(TokArgSeparator) + /* 23 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 30 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 37 */ << H(TokFuncTerminator) + /* 38 */ << H(TokFuncTerminator) + /* 39 */ << H(TokValueTerminator)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("function call with parenthesized argument") + << "VAR = $$bar(blubb (yo, man) blabb, nope)" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") + /* 25 */ << H(TokLiteral | TokNewStr) << S(L"(yo,") + /* 31 */ << H(TokLiteral | TokNewStr) << S(L"man)") + /* 37 */ << H(TokLiteral | TokNewStr) << S(L"blabb") + /* 44 */ << H(TokArgSeparator) + /* 45 */ << H(TokLiteral | TokNewStr) << S(L"nope") + /* 51 */ << H(TokFuncTerminator) + /* 52 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("separate literal and expansion") + << "VAR = foo $$bar" + << TS( + /* 0 */ << ASSIGN_VAR(2) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokVariable | TokNewStr) << HS(L"bar") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("separate expansion and literal") + << "VAR = $$bar foo" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("joined literal and expansion") + << "VAR = foo$$bar" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokVariable) << HS(L"bar") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("joined expansion and literal") + << "VAR = $${bar}foo" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") + /* 18 */ << H(TokLiteral) << S(L"foo") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("plain variable expansion with funny name and literal") + << "VAR = $$az_AZ_09.dot/nix" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot") + /* 27 */ << H(TokLiteral) << S(L"/nix") + /* 33 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("braced variable expansion with funny name") + << "VAR = $${az_AZ_09.dot/nix}" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot/nix") + /* 31 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("quoted joined literal and expansion") + << "VAR = 'foo$$bar'" + << TS( + /* 0 */ << ASSIGN_VAR(0) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 16 */ << H(TokVariable | TokQuoted) << HS(L"bar") + /* 23 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("assignment with expansion in variable name") + << "VAR$$EXTRA =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokVariable) << HS(L"EXTRA") + /* 18 */ << H(TokAssign) << H(0) + /* 20 */ << H(TokValueTerminator)) + << "" + << true; +} + +void tst_qmakelib::addParseConditions() +{ + QTest::newRow("one test") + << "foo" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("wildcard-test") + << "foo-*" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo-*") + /* 11 */ << H(TokCondition)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("one quoted test") + << "\"foo\"" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("two tests") + << "foo\nbar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokLine) << H(2) + /* 12 */ << H(TokHashLiteral) << HS(L"bar") + /* 19 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("bogus two tests") + << "foo bar\nbaz" + << TS() + << "in:1: Extra characters after test expression." + << false; + + QTest::newRow("test-AND-test") + << "foo:bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-OR-test") + << " foo | bar " + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokOr) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("NOT-test") + << "!foo" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokNot) + /* 3 */ << H(TokHashLiteral) << HS(L"foo") + /* 10 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("NOT-NOT-test") + << "!!foo" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("quoted-NOT-test") + << "\"!foo\"" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokNot) + /* 3 */ << H(TokHashLiteral) << HS(L"foo") + /* 10 */ << H(TokCondition)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("NOT-quoted-test") + << "!\"foo\"" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokNot) + /* 3 */ << H(TokHashLiteral) << HS(L"foo") + /* 10 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-AND-NOT-test") + << "foo:!bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokNot) + /* 12 */ << H(TokHashLiteral) << HS(L"bar") + /* 19 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-assignment") + << "foo\nVAR=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokLine) << H(2) + /* 12 */ << H(TokHashLiteral) << HS(L"VAR") + /* 19 */ << H(TokAssign) << H(0) + /* 21 */ << H(TokValueTerminator)) + << "" + << true; + + QTest::newRow("test-AND-assignment") + << "foo: VAR =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokBranch) + /* 11 */ /* then branch */ << I(11) + /* 13 */ << H(TokHashLiteral) << HS(L"VAR") + /* 20 */ << H(TokAssign) << H(0) + /* 22 */ << H(TokValueTerminator) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-else-test") + << "foo\nelse: bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokBranch) + /* 11 */ /* then branch */ << I(0) + /* 13 */ /* else branch */ << I(11) + /* 15 */ << H(TokLine) << H(2) + /* 17 */ << H(TokHashLiteral) << HS(L"bar") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("function-else-test") + << "foo()\nelse: bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(0) + /* 14 */ /* else branch */ << I(11) + /* 16 */ << H(TokLine) << H(2) + /* 18 */ << H(TokHashLiteral) << HS(L"bar") + /* 25 */ << H(TokCondition) + /* 26 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-AND-test-else-test") + << "foo:bar\nelse: baz" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokCondition) + /* 19 */ << H(TokBranch) + /* 20 */ /* then branch */ << I(0) + /* 22 */ /* else branch */ << I(11) + /* 24 */ << H(TokLine) << H(2) + /* 26 */ << H(TokHashLiteral) << HS(L"baz") + /* 33 */ << H(TokCondition) + /* 34 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-AND-test-else-test-else-test-function") + << "foo:bar\nelse: baz\nelse: bak\nbuzz()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokCondition) + /* 19 */ << H(TokBranch) + /* 20 */ /* then branch */ << I(0) + /* 22 */ /* else branch */ << I(27) + /* 24 */ << H(TokLine) << H(2) + /* 26 */ << H(TokHashLiteral) << HS(L"baz") + /* 33 */ << H(TokCondition) + /* 34 */ << H(TokBranch) + /* 35 */ /* then branch */ << I(0) + /* 37 */ /* else branch */ << I(11) + /* 39 */ << H(TokLine) << H(3) + /* 41 */ << H(TokHashLiteral) << HS(L"bak") + /* 48 */ << H(TokCondition) + /* 49 */ << H(TokTerminator) + /* 50 */ << H(TokTerminator) + /* 51 */ << H(TokLine) << H(4) + /* 53 */ << H(TokHashLiteral) << HS(L"buzz") + /* 61 */ << H(TokTestCall) + /* 62 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("test-assignment-else-assignment") + << "foo: VAR =\nelse: VAR=" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokBranch) + /* 11 */ /* then branch */ << I(11) + /* 13 */ << H(TokHashLiteral) << HS(L"VAR") + /* 20 */ << H(TokAssign) << H(0) + /* 22 */ << H(TokValueTerminator) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(13) + /* 26 */ << H(TokLine) << H(2) + /* 28 */ << H(TokHashLiteral) << HS(L"VAR") + /* 35 */ << H(TokAssign) << H(0) + /* 37 */ << H(TokValueTerminator) + /* 38 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-else-test-assignment") + << "foo\nelse: bar: VAR =" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokBranch) + /* 11 */ /* then branch */ << I(0) + /* 13 */ /* else branch */ << I(27) + /* 15 */ << H(TokLine) << H(2) + /* 17 */ << H(TokHashLiteral) << HS(L"bar") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokBranch) + /* 26 */ /* then branch */ << I(11) + /* 28 */ << H(TokHashLiteral) << HS(L"VAR") + /* 35 */ << H(TokAssign) << H(0) + /* 37 */ << H(TokValueTerminator) + /* 38 */ << H(TokTerminator) + /* 39 */ /* else branch */ << I(0) + /* 41 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("one function") + << "foo()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("one function (with spaces)") + << " foo( ) " + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("unterminated function call") + << "foo(\nfoo" + << TS() + << "in:1: Missing closing parenthesis in function call" + << false; + + QTest::newRow("function with arguments") + << "foo(blah, hi ho)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah") + /* 16 */ << H(TokArgSeparator) + /* 17 */ << H(TokLiteral | TokNewStr) << S(L"hi") + /* 21 */ << H(TokLiteral | TokNewStr) << S(L"ho") + /* 25 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("function with empty arguments") + << "foo(,)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokArgSeparator) + /* 11 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("function with funny arguments") + << "foo(blah\\, \"hi , \\ho\" ,uh\\ ,\\oh ,, )" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah\\") + /* 17 */ << H(TokArgSeparator) + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi , \\ho") + /* 29 */ << H(TokArgSeparator) + /* 30 */ << H(TokLiteral | TokNewStr) << S(L"uh\\") + /* 35 */ << H(TokArgSeparator) + /* 36 */ << H(TokLiteral | TokNewStr) << S(L"\\oh") + /* 41 */ << H(TokArgSeparator) + /* 42 */ << H(TokArgSeparator) + /* 43 */ << H(TokFuncTerminator)) + << "WARNING: in:1: Unescaped backslashes are deprecated\n" + "WARNING: in:1: Unescaped backslashes are deprecated\n" + "WARNING: in:1: Unescaped backslashes are deprecated\n" + "WARNING: in:1: Unescaped backslashes are deprecated" + << true; + + QTest::newRow("function with nested call") + << "foo($$blah(hi ho))" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncName | TokNewStr) << HS(L"blah") + /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi") + /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ho") + /* 26 */ << H(TokFuncTerminator) + /* 27 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("stand-alone parentheses") + << "()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestCall) + /* 3 */ << H(TokFuncTerminator)) + << "in:1: Opening parenthesis without prior test name." + << false; + + QTest::newRow("bogus test and function") + << "foo bar()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestCall) + /* 3 */ << H(TokFuncTerminator)) + << "in:1: Extra characters after test expression." + << false; + + // This is a rather questionable "feature" + QTest::newRow("two functions") + << "foo() bar()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokTestCall) + /* 19 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("function-AND-test") + << "foo():bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokTestCall) + /* 10 */ << H(TokFuncTerminator) + /* 11 */ << H(TokAnd) + /* 12 */ << H(TokHashLiteral) << HS(L"bar") + /* 19 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-AND-function") + << "foo:bar()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokHashLiteral) << HS(L"bar") + /* 18 */ << H(TokTestCall) + /* 19 */ << H(TokFuncTerminator)) + << "" + << true; + + QTest::newRow("NOT-function-AND-test") + << "!foo():bar" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokNot) + /* 3 */ << H(TokHashLiteral) << HS(L"foo") + /* 10 */ << H(TokTestCall) + /* 11 */ << H(TokFuncTerminator) + /* 12 */ << H(TokAnd) + /* 13 */ << H(TokHashLiteral) << HS(L"bar") + /* 20 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("test-AND-NOT-function") + << "foo:!bar()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"foo") + /* 9 */ << H(TokCondition) + /* 10 */ << H(TokAnd) + /* 11 */ << H(TokNot) + /* 12 */ << H(TokHashLiteral) << HS(L"bar") + /* 19 */ << H(TokTestCall) + /* 20 */ << H(TokFuncTerminator)) + << "" + << true; +} + +void tst_qmakelib::addParseControlStatements() +{ + QTest::newRow("for(VAR, LIST) loop") + << "for(VAR, LIST)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"VAR") + /* 9 */ /* iterator */ << I(7) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"LIST") + /* 17 */ << H(TokValueTerminator) + /* 18 */ /* body */ << I(1) + /* 20 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("for(ever) loop") + << "for(ever)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(1) + /* 19 */ << H(TokTerminator)) + << "" + << true; + + // This is a rather questionable "feature" + QTest::newRow("for($$blub) loop") + << "for($$blub)" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokVariable | TokNewStr) << HS(L"blub") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(1) + /* 19 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-for-test-else-test") + << "true:for(VAR, LIST): true\nelse: true" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(31) + /* 14 */ << H(TokForLoop) << HS(L"VAR") + /* 21 */ /* iterator */ << I(7) + /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") + /* 29 */ << H(TokValueTerminator) + /* 30 */ /* body */ << I(12) + /* 32 */ << H(TokLine) << H(1) + /* 34 */ << H(TokHashLiteral) << HS(L"true") + /* 42 */ << H(TokCondition) + /* 43 */ << H(TokTerminator) + /* 44 */ << H(TokTerminator) + /* 45 */ /* else branch */ << I(12) + /* 47 */ << H(TokLine) << H(2) + /* 49 */ << H(TokHashLiteral) << HS(L"true") + /* 57 */ << H(TokCondition) + /* 58 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("next()") + << "for(ever): next()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(4) + /* 19 */ << H(TokLine) << H(1) + /* 21 */ << H(TokNext) + /* 22 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("break()") + << "for(ever): break()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(4) + /* 19 */ << H(TokLine) << H(1) + /* 21 */ << H(TokBreak) + /* 22 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("top-level return()") + << "return()" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokReturn)) + << "" + << true; + + QTest::newRow("else") + << "else" + << TS() + << "in:1: Unexpected 'else'." + << false; + + QTest::newRow("test-{else}") + << "test { else }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(0)) + << "in:1: Unexpected 'else'." + << false; + + QTest::newRow("defineTest-{else}") + << "defineTest(fn) { else }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"fn") + /* 8 */ /* body */ << I(1) + /* 10 */ << H(TokTerminator)) + << "in:1: Unexpected 'else'." + << false; + + QTest::newRow("for-else") + << "for(ever) { else }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(1) + /* 19 */ << H(TokTerminator)) + << "in:1: Unexpected 'else'." + << false; + + QTest::newRow("double-test-else") + << "foo bar\nelse" + << TS( + /* 0 */ << H(TokBranch) + /* 1 */ /* then branch */ << I(0) + /* 3 */ /* else branch */ << I(1) // This seems weird + /* 5 */ << H(TokTerminator)) + << "in:1: Extra characters after test expression." + << false; + + QTest::newRow("test-function-else") + << "foo bar()\nelse" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestCall) // This seems pointless + /* 3 */ << H(TokFuncTerminator) + /* 4 */ << H(TokBranch) + /* 5 */ /* then branch */ << I(0) + /* 7 */ /* else branch */ << I(1) // This seems weird + /* 9 */ << H(TokTerminator)) + << "in:1: Extra characters after test expression." + << false; +} + +void tst_qmakelib::addParseBraces() +{ + QTest::newRow("{}") + << "{ }" + << TS() + << "" + << true; + + QTest::newRow("{}-newlines") + << "\n\n{ }\n\n" + << TS() + << "" + << true; + + QTest::newRow("{") + << "{" + << TS() + << "in:2: Missing closing brace(s)." + << false; + + QTest::newRow("test {") + << "test {" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(0)) + << "in:2: Missing closing brace(s)." + << false; + + QTest::newRow("}") + << "}" + << TS() + << "in:1: Excess closing brace." + << false; + + QTest::newRow("{test}") + << "{ true }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("{test-newlines}") + << "{\ntrue\n}" + << TS( + /* 0 */ << H(TokLine) << H(2) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("{assignment-test}-test") + << "{ VAR = { foo } bar } true" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(4) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{") + /* 14 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 19 */ << H(TokLiteral | TokNewStr) << S(L"}") + /* 22 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 27 */ << H(TokValueTerminator) + /* 28 */ << H(TokHashLiteral) << HS(L"true") + /* 36 */ << H(TokCondition)) + << "" + << true; + + QTest::newRow("assignment with excess opening brace") + << "VAR = { { foo }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"VAR") + /* 9 */ << H(TokAssign) << H(4) + /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{") + /* 14 */ << H(TokLiteral | TokNewStr) << S(L"{") + /* 17 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 22 */ << H(TokLiteral | TokNewStr) << S(L"}") + /* 25 */ << H(TokValueTerminator)) + << "WARNING: in:1: Possible braces mismatch" + << true; + + QTest::newRow("test-{}") + << "true {}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{newlines}") + << "true {\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{test}") + << "true { true }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(10) + /* 14 */ << H(TokHashLiteral) << HS(L"true") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test:-{test}") + << "true: { true }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(10) + /* 14 */ << H(TokHashLiteral) << HS(L"true") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "WARNING: in:1: Excess colon in front of opening brace." + << true; + + QTest::newRow("test-{test-newlines}") + << "true {\ntrue\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(12) + /* 14 */ << H(TokLine) << H(2) + /* 16 */ << H(TokHashLiteral) << HS(L"true") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokTerminator) + /* 26 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test:-{test-newlines}") + << "true: {\ntrue\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(12) + /* 14 */ << H(TokLine) << H(2) + /* 16 */ << H(TokHashLiteral) << HS(L"true") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokTerminator) + /* 26 */ /* else branch */ << I(0)) + << "WARNING: in:1: Excess colon in front of opening brace." + << true; + + QTest::newRow("test-{assignment}") + << "true { VAR = {foo} }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(18) + /* 14 */ << H(TokHashLiteral) << HS(L"VAR") + /* 21 */ << H(TokAssign) << H(0) + /* 23 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") + /* 30 */ << H(TokValueTerminator) + /* 31 */ << H(TokTerminator) + /* 32 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{test-assignment}") + << "true { true: VAR = {foo} }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(33) + /* 14 */ << H(TokHashLiteral) << HS(L"true") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokBranch) + /* 24 */ /* then branch */ << I(18) + /* 26 */ << H(TokHashLiteral) << HS(L"VAR") + /* 33 */ << H(TokAssign) << H(0) + /* 35 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") + /* 42 */ << H(TokValueTerminator) + /* 43 */ << H(TokTerminator) + /* 44 */ /* else branch */ << I(0) + /* 46 */ << H(TokTerminator) + /* 47 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{assignment-newlines}") + << "true {\nVAR = {foo}\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(20) + /* 14 */ << H(TokLine) << H(2) + /* 16 */ << H(TokHashLiteral) << HS(L"VAR") + /* 23 */ << H(TokAssign) << H(0) + /* 25 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") + /* 32 */ << H(TokValueTerminator) + /* 33 */ << H(TokTerminator) + /* 34 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-{}-else-test-{}") + << "true {} else: true {}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(18) + /* 17 */ << H(TokLine) << H(1) + /* 19 */ << H(TokHashLiteral) << HS(L"true") + /* 27 */ << H(TokCondition) + /* 28 */ << H(TokBranch) + /* 29 */ /* then branch */ << I(1) + /* 31 */ << H(TokTerminator) + /* 32 */ /* else branch */ << I(0) + /* 34 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-{}-else-test-{}-newlines") + << "true {\n}\nelse: true {\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(1) + /* 14 */ << H(TokTerminator) + /* 15 */ /* else branch */ << I(18) + /* 17 */ << H(TokLine) << H(3) + /* 19 */ << H(TokHashLiteral) << HS(L"true") + /* 27 */ << H(TokCondition) + /* 28 */ << H(TokBranch) + /* 29 */ /* then branch */ << I(1) + /* 31 */ << H(TokTerminator) + /* 32 */ /* else branch */ << I(0) + /* 34 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-{test}-else-test-{}-newlines") + << "true {\ntrue\n}\nelse: true {\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(12) + /* 14 */ << H(TokLine) << H(2) + /* 16 */ << H(TokHashLiteral) << HS(L"true") + /* 24 */ << H(TokCondition) + /* 25 */ << H(TokTerminator) + /* 26 */ /* else branch */ << I(18) + /* 28 */ << H(TokLine) << H(4) + /* 30 */ << H(TokHashLiteral) << HS(L"true") + /* 38 */ << H(TokCondition) + /* 39 */ << H(TokBranch) + /* 40 */ /* then branch */ << I(1) + /* 42 */ << H(TokTerminator) + /* 43 */ /* else branch */ << I(0) + /* 45 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("for-{next}") + << "for(ever) { next() }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(4) + /* 19 */ << H(TokLine) << H(1) + /* 21 */ << H(TokNext) + /* 22 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("for:-{next}") + << "for(ever): { next() }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokForLoop) << HS(L"") + /* 6 */ /* iterator */ << I(9) + /* 8 */ << H(TokHashLiteral) << HS(L"ever") + /* 16 */ << H(TokValueTerminator) + /* 17 */ /* body */ << I(4) + /* 19 */ << H(TokLine) << H(1) + /* 21 */ << H(TokNext) + /* 22 */ << H(TokTerminator)) + << "WARNING: in:1: Excess colon in front of opening brace." + << true; + + QTest::newRow("test-for-{test-else-test-newlines}") + << "true:for(VAR, LIST) {\ntrue\nelse: true\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(48) + /* 14 */ << H(TokForLoop) << HS(L"VAR") + /* 21 */ /* iterator */ << I(7) + /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") + /* 29 */ << H(TokValueTerminator) + /* 30 */ /* body */ << I(29) + /* 32 */ << H(TokLine) << H(2) + /* 34 */ << H(TokHashLiteral) << HS(L"true") + /* 42 */ << H(TokCondition) + /* 43 */ << H(TokBranch) + /* 44 */ /* then branch */ << I(0) + /* 46 */ /* else branch */ << I(12) + /* 48 */ << H(TokLine) << H(3) + /* 50 */ << H(TokHashLiteral) << HS(L"true") + /* 58 */ << H(TokCondition) + /* 59 */ << H(TokTerminator) + /* 60 */ << H(TokTerminator) + /* 61 */ << H(TokTerminator) + /* 62 */ /* else branch */ << I(0)) + << "" + << true; + + QTest::newRow("test-for-{test-else-test}") + << "true:for(VAR, LIST) { true\nelse: true }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"true") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(48) + /* 14 */ << H(TokForLoop) << HS(L"VAR") + /* 21 */ /* iterator */ << I(7) + /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") + /* 29 */ << H(TokValueTerminator) + /* 30 */ /* body */ << I(29) + /* 32 */ << H(TokLine) << H(1) + /* 34 */ << H(TokHashLiteral) << HS(L"true") + /* 42 */ << H(TokCondition) + /* 43 */ << H(TokBranch) + /* 44 */ /* then branch */ << I(0) + /* 46 */ /* else branch */ << I(12) + /* 48 */ << H(TokLine) << H(2) + /* 50 */ << H(TokHashLiteral) << HS(L"true") + /* 58 */ << H(TokCondition) + /* 59 */ << H(TokTerminator) + /* 60 */ << H(TokTerminator) + /* 61 */ << H(TokTerminator) + /* 62 */ /* else branch */ << I(0)) + << "" + << true; +} + +void tst_qmakelib::addParseCustomFunctions() +{ + QTest::newRow("defineTest-{newlines}") + << "defineTest(test) {\n}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"test") + /* 10 */ /* body */ << I(1) + /* 12 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("defineTest:-test") + << "defineTest(test): test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"test") + /* 10 */ /* body */ << I(12) + /* 12 */ << H(TokLine) << H(1) + /* 14 */ << H(TokHashLiteral) << HS(L"test") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("defineTest-{test}") + << "defineTest(test) { test }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"test") + /* 10 */ /* body */ << I(12) + /* 12 */ << H(TokLine) << H(1) + /* 14 */ << H(TokHashLiteral) << HS(L"test") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("defineTest-{return}") + << "defineTest(test) { return() }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokTestDef) << HS(L"test") + /* 10 */ /* body */ << I(4) + /* 12 */ << H(TokLine) << H(1) + /* 14 */ << H(TokReturn) + /* 15 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("defineReplace-{return-stuff}") + << "defineReplace(stuff) { return(foo bar) }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokReplaceDef) << HS(L"stuff") + /* 11 */ /* body */ << I(14) + /* 13 */ << H(TokLine) << H(1) + /* 15 */ << H(TokLiteral | TokNewStr) << S(L"foo") + /* 20 */ << H(TokLiteral | TokNewStr) << S(L"bar") + /* 25 */ << H(TokReturn) + /* 26 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-AND-defineTest-{}") + << "test: defineTest(test) {}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokAnd) + /* 12 */ << H(TokTestDef) << HS(L"test") + /* 20 */ /* body */ << I(1) + /* 22 */ << H(TokTerminator)) + << "" + << true; + + QTest::newRow("test-OR-defineTest-{}") + << "test| defineTest(test) {}" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokOr) + /* 12 */ << H(TokTestDef) << HS(L"test") + /* 20 */ /* body */ << I(1) + /* 22 */ << H(TokTerminator)) + << "" + << true; +} + +void tst_qmakelib::addParseAbuse() +{ + QTest::newRow("!") + << "" + << TS() + << "" + << true; + + QTest::newRow("|") + << "" + << TS() + << "" + << true; + + QTest::newRow(":") + << "" + << TS() + << "" + << true; + + QTest::newRow("NOT-assignment") + << "!VAR =" + << TS() + << "in:1: Unexpected NOT operator in front of assignment." + << false; + + QTest::newRow("NOT-{}") + << "!{}" + << TS() + << "in:1: Unexpected NOT operator in front of opening brace." + << false; + + QTest::newRow("NOT-else") + << "test\n!else {}" + << TS() + << "in:2: Unexpected NOT operator in front of else." + << false; + + QTest::newRow("NOT-for-{}") + << "!for(ever) {}" + << TS() + << "in:1: Unexpected NOT operator in front of for()." + << false; + + QTest::newRow("NOT-defineTest-{}") + << "!defineTest(test) {}" + << TS() + << "in:1: Unexpected NOT operator in front of function definition." + << false; + + QTest::newRow("AND-test") + << ":test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition)) + << "in:1: AND operator without prior condition." + << false; + + QTest::newRow("test-AND-else") + << "test:else" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition)) + << "in:1: Unexpected AND operator in front of else." + << false; + + QTest::newRow("test-AND-AND-test") + << "test::test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokAnd) + /* 12 */ << H(TokHashLiteral) << HS(L"test") + /* 20 */ << H(TokCondition)) + << "WARNING: in:1: Stray AND operator in front of AND operator." + << true; + + QTest::newRow("test-AND-OR-test") + << "test:|test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokOr) + /* 12 */ << H(TokHashLiteral) << HS(L"test") + /* 20 */ << H(TokCondition)) + << "WARNING: in:1: Stray AND operator in front of OR operator." + << true; + + QTest::newRow("test-{AND-test}") + << "test { :test }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(10) + /* 14 */ << H(TokHashLiteral) << HS(L"test") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "in:1: AND operator without prior condition." + << false; + + QTest::newRow("test-OR-assignment") + << "foo| VAR =" + << TS() + << "in:1: Unexpected OR operator in front of assignment." + << false; + + QTest::newRow("test-OR-{}") + << "foo|{}" + << TS() + << "in:1: Unexpected OR operator in front of opening brace." + << false; + + QTest::newRow("test-OR-for") + << "foo|for(ever) {}" + << TS() + << "in:1: Unexpected OR operator in front of for()." + << false; + + QTest::newRow("OR-test") + << "|test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition)) + << "in:1: OR operator without prior condition." + << false; + + QTest::newRow("test-OR-else") + << "test|else" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition)) + << "in:1: Unexpected OR operator in front of else." + << false; + + QTest::newRow("test-OR-OR-test") + << "test||test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokOr) + /* 12 */ << H(TokHashLiteral) << HS(L"test") + /* 20 */ << H(TokCondition)) + << "WARNING: in:1: Stray OR operator in front of OR operator." + << true; + + QTest::newRow("test-OR-AND-test") + << "test|:test" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokAnd) + /* 12 */ << H(TokHashLiteral) << HS(L"test") + /* 20 */ << H(TokCondition)) + << "WARNING: in:1: Stray OR operator in front of AND operator." + << true; + + QTest::newRow("test-{OR-test}") + << "test { |test }" + << TS( + /* 0 */ << H(TokLine) << H(1) + /* 2 */ << H(TokHashLiteral) << HS(L"test") + /* 10 */ << H(TokCondition) + /* 11 */ << H(TokBranch) + /* 12 */ /* then branch */ << I(10) + /* 14 */ << H(TokHashLiteral) << HS(L"test") + /* 22 */ << H(TokCondition) + /* 23 */ << H(TokTerminator) + /* 24 */ /* else branch */ << I(0)) + << "in:1: OR operator without prior condition." + << false; +} + +void tst_qmakelib::proParser_data() +{ + QTest::addColumn("in"); + QTest::addColumn("out"); + QTest::addColumn("msgs"); + QTest::addColumn("ok"); + + QTest::newRow("empty") + << "" + << TS() + << "" + << true; + + QTest::newRow("empty (whitespace)") + << " \t \t" + << TS() + << "" + << true; + + addParseOperators(); // Variable operators + + addParseValues(); + + addParseConditions(); // "Tests" + + addParseControlStatements(); + + addParseBraces(); + + addParseCustomFunctions(); + + addParseAbuse(); // Mostly operator abuse + + // option() (these produce no tokens) + + QTest::newRow("option(host_build)") + << "option(host_build)" + << TS() + << "" + << true; + + QTest::newRow("option()") + << "option()" + << TS() + << "in:1: option() requires one literal argument." + << false; + + QTest::newRow("option(host_build magic)") + << "option(host_build magic)" + << TS() + << "in:1: option() requires one literal argument." + << false; + + QTest::newRow("option(host_build, magic)") + << "option(host_build, magic)" + << TS() + << "in:1: option() requires one literal argument." + << false; + + QTest::newRow("option($$OPTION)") + << "option($$OPTION)" + << TS() + << "in:1: option() requires one literal argument." + << false; + + QTest::newRow("{option(host_build)}") + << "{option(host_build)}" + << TS() + << "in:1: option() must appear outside any control structures." + << false; +} + +QT_WARNING_POP + +void tst_qmakelib::proParser() +{ + QFETCH(QString, in); + QFETCH(QString, out); + QFETCH(QString, msgs); + QFETCH(bool, ok); + + bool verified = true; + QMakeTestHandler handler; + handler.setExpectedMessages(msgs.split('\n', QString::SkipEmptyParts)); + QMakeVfs vfs; + QMakeParser parser(0, &vfs, &handler); + ProFile *pro = parser.parsedProBlock(in, "in", 1, QMakeParser::FullGrammar); + if (handler.printedMessages()) { + qWarning("Got unexpected message(s)"); + verified = false; + } + QStringList missingMsgs = handler.expectedMessages(); + if (!missingMsgs.isEmpty()) { + foreach (const QString &msg, missingMsgs) + qWarning("Missing message: %s", qPrintable(msg)); + verified = false; + } + if (pro->isOk() != ok) { + static const char * const lbl[] = { "failure", "success" }; + qWarning("Expected %s, got %s", lbl[int(ok)], lbl[1 - int(ok)]); + verified = false; + } + if (pro->items() != out && (ok || !out.isEmpty())) { + qWarning("Bytecode mismatch.\nActual:%s\nExpected:%s", + qPrintable(QMakeParser::formatProBlock(pro->items())), + qPrintable(QMakeParser::formatProBlock(out))); + verified = false; + } + pro->deref(); + QVERIFY(verified); +} diff --git a/tests/auto/tools/qmakelib/qmakelib.pro b/tests/auto/tools/qmakelib/qmakelib.pro index e7807838aa..f1b8dfef3d 100644 --- a/tests/auto/tools/qmakelib/qmakelib.pro +++ b/tests/auto/tools/qmakelib/qmakelib.pro @@ -6,11 +6,19 @@ QT = core testlib INCLUDEPATH += ../../../../qmake/library VPATH += ../../../../qmake/library +HEADERS += \ + tst_qmakelib.h + SOURCES += \ tst_qmakelib.cpp \ + parsertest.cpp \ + evaltest.cpp \ ioutils.cpp \ proitems.cpp \ qmakevfs.cpp \ - qmakeparser.cpp + qmakeparser.cpp \ + qmakeglobals.cpp \ + qmakebuiltins.cpp \ + qmakeevaluator.cpp -DEFINES += PROPARSER_DEBUG +DEFINES += PROPARSER_DEBUG PROEVALUATOR_FULL PROEVALUATOR_SETENV diff --git a/tests/auto/tools/qmakelib/testdata/cat/file1.txt b/tests/auto/tools/qmakelib/testdata/cat/file1.txt new file mode 100644 index 0000000000..e3e4cd41b6 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/cat/file1.txt @@ -0,0 +1,2 @@ +"Hello, world." +foo bar baz diff --git a/tests/auto/tools/qmakelib/testdata/cat/file2.txt b/tests/auto/tools/qmakelib/testdata/cat/file2.txt new file mode 100644 index 0000000000..18483311e6 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/cat/file2.txt @@ -0,0 +1,5 @@ +foo bar baz +"Hello, ' world." post +'Hello, " world.' post +\" \' \\ \a \ nix +" " diff --git a/tests/auto/tools/qmakelib/testdata/files/dir/file1.txt b/tests/auto/tools/qmakelib/testdata/files/dir/file1.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/tools/qmakelib/testdata/files/dir/file2.txt b/tests/auto/tools/qmakelib/testdata/files/dir/file2.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/tools/qmakelib/testdata/files/file1.txt b/tests/auto/tools/qmakelib/testdata/files/file1.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/tools/qmakelib/testdata/files/file2.txt b/tests/auto/tools/qmakelib/testdata/files/file2.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/tools/qmakelib/testdata/files/other.txt b/tests/auto/tools/qmakelib/testdata/files/other.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/tools/qmakelib/testdata/fromfile/badfile.prx b/tests/auto/tools/qmakelib/testdata/fromfile/badfile.prx new file mode 100644 index 0000000000..a916f21587 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/fromfile/badfile.prx @@ -0,0 +1 @@ +error("fail!") diff --git a/tests/auto/tools/qmake/testdata/functions/infiletest.pro b/tests/auto/tools/qmakelib/testdata/fromfile/infile.prx similarity index 100% rename from tests/auto/tools/qmake/testdata/functions/infiletest.pro rename to tests/auto/tools/qmakelib/testdata/fromfile/infile.prx diff --git a/tests/auto/tools/qmakelib/testdata/include/inc.pri b/tests/auto/tools/qmakelib/testdata/include/inc.pri new file mode 100644 index 0000000000..1f1b3a287f --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/include/inc.pri @@ -0,0 +1,8 @@ +VAR = val +.VAR = nope + +fake-*: MATCH = 1 + +defineTest(func) { + message("say hi!") +} diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/fake-g++/qmake.conf b/tests/auto/tools/qmakelib/testdata/mkspecs/fake-g++/qmake.conf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/fake-g++/qmake.conf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_post.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_post.prf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_post.prf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_pre.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_pre.prf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/default_pre.prf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_post.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_post.prf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_post.prf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_pre.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_pre.prf new file mode 100644 index 0000000000..d7a17d2429 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/spec_pre.prf @@ -0,0 +1 @@ +# Nothing here diff --git a/tests/auto/tools/qmakelib/testdata/mkspecs/features/testfeat.prf b/tests/auto/tools/qmakelib/testdata/mkspecs/features/testfeat.prf new file mode 100644 index 0000000000..57c9a0d783 --- /dev/null +++ b/tests/auto/tools/qmakelib/testdata/mkspecs/features/testfeat.prf @@ -0,0 +1 @@ +VAR = foo bar diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.cpp b/tests/auto/tools/qmakelib/tst_qmakelib.cpp index 1c6d43338d..3da48815fb 100644 --- a/tests/auto/tools/qmakelib/tst_qmakelib.cpp +++ b/tests/auto/tools/qmakelib/tst_qmakelib.cpp @@ -31,37 +31,112 @@ ** ****************************************************************************/ -#include +#include "tst_qmakelib.h" #include -#include -#include -#include - -#include using namespace QMakeInternal; -class tst_qmakelib : public QObject +void tst_qmakelib::initTestCase() { - Q_OBJECT + m_indir = QFINDTESTDATA("testdata"); + m_outdir = m_indir + QLatin1String("_build"); + m_env.insert(QStringLiteral("E1"), QStringLiteral("env var")); +#ifdef Q_OS_WIN + m_env.insert(QStringLiteral("COMSPEC"), qgetenv("COMSPEC")); +#endif + m_prop.insert(ProKey("P1"), ProString("prop val")); + m_prop.insert(ProKey("QT_HOST_DATA/get"), ProString(m_indir)); -public: - tst_qmakelib() {} - virtual ~tst_qmakelib() {} + QVERIFY(!m_indir.isEmpty()); + QVERIFY(QDir(m_outdir).removeRecursively()); + QVERIFY(QDir().mkpath(m_outdir)); +} -private slots: - void quoteArgUnix_data(); - void quoteArgUnix(); - void quoteArgWin_data(); - void quoteArgWin(); - void pathUtils(); +void tst_qmakelib::cleanupTestCase() +{ + QVERIFY(QDir(m_outdir).removeRecursively()); +} - void proStringList(); +void tst_qmakelib::proString() +{ + QString qs1(QStringLiteral("this is a string")); - void proParser_data(); - void proParser(); -}; + ProString s1(qs1); + QCOMPARE(s1.toQString(), QStringLiteral("this is a string")); + + ProString s2(qs1, 5, 8); + QCOMPARE(s2.toQString(), QStringLiteral("is a str")); + + QCOMPARE(s2.hash(), 0x80000000); + qHash(s2); + QCOMPARE(s2.hash(), 90404018U); + + QCOMPARE(s2.mid(0, 10).toQString(), QStringLiteral("is a str")); + QCOMPARE(s2.mid(1, 5).toQString(), QStringLiteral("s a s")); + QCOMPARE(s2.mid(10, 3).toQString(), QStringLiteral("")); + + QString qs2(QStringLiteral(" spacy string ")); + QCOMPARE(ProString(qs2, 3, 13).trimmed().toQString(), QStringLiteral("spacy string")); + QCOMPARE(ProString(qs2, 1, 17).trimmed().toQString(), QStringLiteral("spacy string")); + + QVERIFY(s2.toQStringRef().string()->isSharedWith(qs1)); + s2.prepend(ProString("there ")); + QCOMPARE(s2.toQString(), QStringLiteral("there is a str")); + QVERIFY(!s2.toQStringRef().string()->isSharedWith(qs1)); + + ProString s3("this is a longish string with bells and whistles"); + s3 = s3.mid(18, 17); + // Prepend to detached string with lots of spare space in it. + s3.prepend(ProString("another ")); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells")); + + // Note: The string still has plenty of spare space. + s3.append(QLatin1Char('.')); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells.")); + s3.append(QLatin1String(" eh?")); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh?")); + + s3.append(ProString(" yeah!")); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh? yeah!")); + + bool pending = false; // Not in string, but joining => add space + s3.append(ProString("..."), &pending); + QCOMPARE(s3.toQString(), QStringLiteral("another string with bells. eh? yeah! ...")); + QVERIFY(pending); + + ProStringList sl1; + sl1 << ProString("") << ProString("foo") << ProString("barbaz"); + ProString s4a("hallo"); + s4a.append(sl1); + QCOMPARE(s4a.toQString(), QStringLiteral("hallo foo barbaz")); + ProString s4b("hallo"); + pending = false; + s4b.append(sl1, &pending); + QCOMPARE(s4b.toQString(), QStringLiteral("hallo foo barbaz")); + ProString s4c; + pending = false; + s4c.append(sl1, &pending); + QCOMPARE(s4c.toQString(), QStringLiteral(" foo barbaz")); + // bizarreness + ProString s4d("hallo"); + pending = false; + s4d.append(sl1, &pending, true); + QCOMPARE(s4d.toQString(), QStringLiteral("hallo foo barbaz")); + ProString s4e; + pending = false; + s4e.append(sl1, &pending, true); + QCOMPARE(s4e.toQString(), QStringLiteral("foo barbaz")); + + ProStringList sl2; + sl2 << ProString("foo"); + ProString s5; + s5.append(sl2); + QCOMPARE(s5.toQString(), QStringLiteral("foo")); + QVERIFY(s5.toQStringRef().string()->isSharedWith(*sl2.first().toQStringRef().string())); + + QCOMPARE(ProString("one") + ProString(" more"), QStringLiteral("one more")); +} void tst_qmakelib::proStringList() { @@ -171,1940 +246,24 @@ void tst_qmakelib::pathUtils() QCOMPARE(IoUtils::resolvePath(fnbase, fn1), QStringLiteral("/a/unix/file/path")); } -class QMakeHandler : public QMakeParserHandler { -public: - QMakeHandler() : QMakeParserHandler(), printed(false) {} - virtual void message(int type, const QString &msg, const QString &fileName, int lineNo) - { print(fileName, lineNo, type, msg); } - - void setExpectedMessages(const QStringList &msgs) { expected = msgs; } - QStringList expectedMessages() const { return expected; } - - bool printedMessages() const { return printed; } - -private: - void print(const QString &fileName, int lineNo, int type, const QString &msg) - { - QString pfx = ((type & QMakeParserHandler::CategoryMask) == QMakeParserHandler::WarningMessage) - ? QString::fromLatin1("WARNING: ") : QString(); - QString out; - if (lineNo) - out = QStringLiteral("%1%2:%3: %4").arg(pfx, fileName, QString::number(lineNo), msg); - else - out = QStringLiteral("%1%2").arg(pfx, msg); - if (!expected.isEmpty() && expected.first() == out) { - expected.removeAt(0); - return; - } - qWarning("%s", qPrintable(out)); - printed = true; - } - - QStringList expected; - bool printed; -}; - -static QMakeHandler qmakeHandler; - -class TokenStream +void QMakeTestHandler::print(const QString &fileName, int lineNo, int type, const QString &msg) { -public: - TokenStream() {} - QString toString() const { return ts; } - - TokenStream &operator<<(ushort n) { ts += QChar(n); return *this; } - TokenStream &operator<<(uint n) { ts += QChar(n & 0xffff); ts += QChar(n >> 16); return *this; } - TokenStream &operator<<(const QStringRef &s) { ts += s; return *this; } - TokenStream &operator<<(const ProString &s) { return *this << ushort(s.length()) << s.toQStringRef(); } - TokenStream &operator<<(const ProKey &s) { return *this << s.hash() << s.toString(); } - -private: - QString ts; -}; - -#define TS(s) (TokenStream() s).toString() -#define H(n) ushort(n) -#define I(n) uint(n) -#define S(s) ProString(QString::fromWCharArray(s)) -#define HS(s) ProKey(QString::fromWCharArray(s)) - -void tst_qmakelib::proParser_data() -{ - QTest::addColumn("in"); - QTest::addColumn("out"); - QTest::addColumn("msgs"); - QTest::addColumn("ok"); - - QTest::newRow("empty") - << "" - << TS() - << "" - << true; - - QTest::newRow("empty (whitespace)") - << " \t \t" - << TS() - << "" - << true; - - // Variable operators - - QTest::newRow("assign none") - << "VAR =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("append none") - << "VAR +=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAppend) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("unique append none") - << "VAR *=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAppendUnique) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("remove none") - << "VAR -=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokRemove) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("replace empty") - << "VAR ~=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokReplace) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("assignment without variable") - << "=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokAssign) << H(0) - /* 4 */ << H(TokValueTerminator)) - << "in:1: Assignment needs exactly one word on the left hand side." - << false; - - QTest::newRow("assignment with multiple variables") - << "VAR VAR =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokAssign) << H(0) - /* 4 */ << H(TokValueTerminator)) - << "in:1: Assignment needs exactly one word on the left hand side." - << false; - - // Values - -#define ASSIGN_VAR(h) \ - H(TokLine) << H(1) \ - << H(TokHashLiteral) << HS(L"VAR") \ - << H(TokAssign) << H(h) - - QTest::newRow("one literal") - << "VAR = val" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val") - /* 16 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("one literal (squeezed)") - << "VAR=val" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val") - /* 16 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("many literals") - << "VAR = foo barbaz bak hello" - << TS( - /* 0 */ << ASSIGN_VAR(4) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak") - /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello") - /* 36 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("many literals (tab-separated") - << "VAR\t=\tfoo\tbarbaz\tbak\thello" - << TS( - /* 0 */ << ASSIGN_VAR(4) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak") - /* 29 */ << H(TokLiteral | TokNewStr) << S(L"hello") - /* 36 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("one quoted literal") - << "VAR = \"val ue\"" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue") - /* 19 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("quoted literal with missing quote") - << "VAR = val \"ue" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(0) - /* 11 */ << H(TokValueTerminator)) - << "in:1: Missing closing \" quote" - << false; - - QTest::newRow("many quoted literals") - << "VAR = \"foo\" barbaz 'bak hello' \"\"" - << TS( - /* 0 */ << ASSIGN_VAR(3) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak hello") - /* 35 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("many quoted literals (with tabs)") - << "VAR\t=\t\"foo\"\tbarbaz\t'bak\thello'" - << TS( - /* 0 */ << ASSIGN_VAR(3) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"barbaz") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"bak\thello") - /* 35 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("quoted and unquoted spaces") - << " VAR = \"val ue \" " - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"val ue ") - /* 22 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("funny literals") - << "VAR = foo:bar|!baz(blam!, ${foo})" - << TS( - /* 0 */ << ASSIGN_VAR(2) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo:bar|!baz(blam!,") - /* 32 */ << H(TokLiteral | TokNewStr) << S(L"${foo})") - /* 41 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("literals with escapes") - << "VAR = \\{hi\\} \\[ho\\] \\)uh\\( \"\\\\oh\\$\"\\' \\$\\${FOO}" - << TS( - /* 0 */ << ASSIGN_VAR(5) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{hi}") - /* 17 */ << H(TokLiteral | TokNewStr) << S(L"[ho]") - /* 23 */ << H(TokLiteral | TokNewStr) << S(L")uh(") - /* 29 */ << H(TokLiteral | TokNewStr) << S(L"\\oh$'") - /* 36 */ << H(TokLiteral | TokNewStr) << S(L"$${FOO}") - /* 45 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("magic variables") - << "VAR = $$LITERAL_HASH $$LITERAL_DOLLAR $$LITERAL_WHITESPACE $$_FILE_ $$_LINE_" - << TS( - /* 0 */ << ASSIGN_VAR(5) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"#") - /* 14 */ << H(TokLiteral | TokNewStr) << S(L"$") - /* 17 */ << H(TokLiteral | TokNewStr) << S(L"\t") - /* 20 */ << H(TokLiteral | TokNewStr) << S(L"in") - /* 24 */ << H(TokLiteral | TokNewStr) << S(L"1") - /* 27 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("continuations and comments") - << "VAR = foo \\\n bar\n \n" - "GAR = foo \\ # comment\n bar \\\n # comment\n baz \\\n" - "\"quoted \\ #comment\n escape\" \\\n right\\\n after \\\n gorilla!\n \n\n" - "MOO = \\\n kuh # comment\nLOO =\n\n" - "FOO = bar \\\n# comment\n baz \\\n \n# comment\n" - "GAZ=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(2) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 21 */ << H(TokValueTerminator) - /* 22 */ << H(TokLine) << H(4) - /* 24 */ << H(TokHashLiteral) << HS(L"GAR") - /* 31 */ << H(TokAssign) << H(7) - /* 33 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 38 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 43 */ << H(TokLiteral | TokNewStr) << S(L"baz") - /* 48 */ << H(TokLiteral | TokNewStr) << S(L"quoted escape") - /* 64 */ << H(TokLiteral | TokNewStr) << S(L"right") - /* 71 */ << H(TokLiteral | TokNewStr) << S(L"after") - /* 78 */ << H(TokLiteral | TokNewStr) << S(L"gorilla!") - /* 88 */ << H(TokValueTerminator) - /* 89 */ << H(TokLine) << H(15) - /* 91 */ << H(TokHashLiteral) << HS(L"MOO") - /* 98 */ << H(TokAssign) << H(0) - /* 100 */ << H(TokLiteral | TokNewStr) << S(L"kuh") - /* 105 */ << H(TokValueTerminator) - /* 106 */ << H(TokLine) << H(17) - /* 108 */ << H(TokHashLiteral) << HS(L"LOO") - /* 115 */ << H(TokAssign) << H(0) - /* 117 */ << H(TokValueTerminator) - /* 118 */ << H(TokLine) << H(19) - /* 120 */ << H(TokHashLiteral) << HS(L"FOO") - /* 127 */ << H(TokAssign) << H(2) - /* 129 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 134 */ << H(TokLiteral | TokNewStr) << S(L"baz") - /* 139 */ << H(TokValueTerminator) - /* 140 */ << H(TokLine) << H(24) - /* 142 */ << H(TokHashLiteral) << HS(L"GAZ") - /* 149 */ << H(TokAssign) << H(0) - /* 151 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("accidental continuation") - << "VAR0 = \\\n this \\\n is \\\n ok\n" - "VAR1 = \\\n this \\\n is=still \\\n ok\n" - "VAR2 = \\\n this \\\n is \\\n" - "VAR3 = \\\n not ok\n" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR0") - /* 10 */ << H(TokAssign) << H(3) - /* 12 */ << H(TokLiteral | TokNewStr) << S(L"this") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"is") - /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ok") - /* 26 */ << H(TokValueTerminator) - /* 27 */ << H(TokLine) << H(5) - /* 29 */ << H(TokHashLiteral) << HS(L"VAR1") - /* 37 */ << H(TokAssign) << H(3) - /* 39 */ << H(TokLiteral | TokNewStr) << S(L"this") - /* 45 */ << H(TokLiteral | TokNewStr) << S(L"is=still") - /* 55 */ << H(TokLiteral | TokNewStr) << S(L"ok") - /* 59 */ << H(TokValueTerminator) - /* 60 */ << H(TokLine) << H(9) - /* 62 */ << H(TokHashLiteral) << HS(L"VAR2") - /* 70 */ << H(TokAssign) << H(6) - /* 72 */ << H(TokLiteral | TokNewStr) << S(L"this") - /* 78 */ << H(TokLiteral | TokNewStr) << S(L"is") - /* 82 */ << H(TokLiteral | TokNewStr) << S(L"VAR3") - /* 88 */ << H(TokLiteral | TokNewStr) << S(L"=") - /* 91 */ << H(TokLiteral | TokNewStr) << S(L"not") - /* 96 */ << H(TokLiteral | TokNewStr) << S(L"ok") - /* 100 */ << H(TokValueTerminator)) - << "WARNING: in:12: Possible accidental line continuation" - << true; - - QTest::newRow("plain variable expansion") - << "VAR = $$bar" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("braced variable expansion") - << "VAR = $${foo/bar}" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"foo/bar") - /* 22 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("bogus variable expansion") - << "VAR = $$ " - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"") - /* 15 */ << H(TokValueTerminator)) - << "WARNING: in:1: Missing name in expansion" - << true; - - QTest::newRow("bogus braced variable expansion") - << "VAR = $${}" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"") - /* 15 */ << H(TokValueTerminator)) - << "WARNING: in:1: Missing name in expansion" - << true; - - QTest::newRow("unterminated braced variable expansion") - << "VAR = $${FOO" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO") - /* 18 */ << H(TokValueTerminator)) - << "in:1: Missing } terminator [found end-of-line]" - << false; - - QTest::newRow("invalid identifier in braced variable expansion") - << "VAR = $${FOO/BAR+BAZ}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"FOO/BAR") - /* 22 */ << H(TokLiteral) << S(L"+BAZ") - /* 28 */ << H(TokValueTerminator)) - << "in:1: Missing } terminator [found +]" - << false; - - QTest::newRow("property expansion") - << "VAR = $$[bar]" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokProperty | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("environment expansion") - << "VAR = $$(bar)" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokEnvVar | TokNewStr) << S(L"bar") - /* 16 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("plain function call") - << "VAR = $$bar()" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokFuncTerminator) - /* 19 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("braced function call") - << "VAR = $${bar()}" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokFuncTerminator) - /* 19 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("function call with one argument") - << "VAR = $$bar(blubb)" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 25 */ << H(TokFuncTerminator) - /* 26 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("function call with multiple arguments") - << "VAR = $$bar( blubb blubb, hey ,$$you)" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 25 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 32 */ << H(TokArgSeparator) - /* 33 */ << H(TokLiteral | TokNewStr) << S(L"hey") - /* 38 */ << H(TokArgSeparator) - /* 39 */ << H(TokVariable | TokNewStr) << HS(L"you") - /* 46 */ << H(TokFuncTerminator) - /* 47 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("nested function call") - << "VAR = $$foo(yo, $$bar(blubb))" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"foo") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"yo") - /* 22 */ << H(TokArgSeparator) - /* 23 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 30 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 37 */ << H(TokFuncTerminator) - /* 38 */ << H(TokFuncTerminator) - /* 39 */ << H(TokValueTerminator)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("function call with parenthesized argument") - << "VAR = $$bar(blubb (yo, man) blabb, nope)" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokFuncName | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"blubb") - /* 25 */ << H(TokLiteral | TokNewStr) << S(L"(yo,") - /* 31 */ << H(TokLiteral | TokNewStr) << S(L"man)") - /* 37 */ << H(TokLiteral | TokNewStr) << S(L"blabb") - /* 44 */ << H(TokArgSeparator) - /* 45 */ << H(TokLiteral | TokNewStr) << S(L"nope") - /* 51 */ << H(TokFuncTerminator) - /* 52 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("separate literal and expansion") - << "VAR = foo $$bar" - << TS( - /* 0 */ << ASSIGN_VAR(2) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokVariable | TokNewStr) << HS(L"bar") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("separate expansion and literal") - << "VAR = $$bar foo" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("joined literal and expansion") - << "VAR = foo$$bar" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokVariable) << HS(L"bar") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("joined expansion and literal") - << "VAR = $${bar}foo" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"bar") - /* 18 */ << H(TokLiteral) << S(L"foo") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("plain variable expansion with funny name and literal") - << "VAR = $$az_AZ_09.dot/nix" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot") - /* 27 */ << H(TokLiteral) << S(L"/nix") - /* 33 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("braced variable expansion with funny name") - << "VAR = $${az_AZ_09.dot/nix}" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokVariable | TokNewStr) << HS(L"az_AZ_09.dot/nix") - /* 31 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("quoted joined literal and expansion") - << "VAR = 'foo$$bar'" - << TS( - /* 0 */ << ASSIGN_VAR(0) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 16 */ << H(TokVariable | TokQuoted) << HS(L"bar") - /* 23 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("assignment with expansion in variable name") - << "VAR$$EXTRA =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokVariable) << HS(L"EXTRA") - /* 18 */ << H(TokAssign) << H(0) - /* 20 */ << H(TokValueTerminator)) - << "" - << true; - - // Conditionals ("Tests") - - QTest::newRow("one test") - << "foo" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("wildcard-test") - << "foo-*" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo-*") - /* 11 */ << H(TokCondition)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("one quoted test") - << "\"foo\"" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("two tests") - << "foo\nbar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokLine) << H(2) - /* 12 */ << H(TokHashLiteral) << HS(L"bar") - /* 19 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("bogus two tests") - << "foo bar\nbaz" - << TS() - << "in:1: Extra characters after test expression." - << false; - - QTest::newRow("test-AND-test") - << "foo:bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-OR-test") - << " foo | bar " - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokOr) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("NOT-test") - << "!foo" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokNot) - /* 3 */ << H(TokHashLiteral) << HS(L"foo") - /* 10 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("NOT-NOT-test") - << "!!foo" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("quoted-NOT-test") - << "\"!foo\"" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokNot) - /* 3 */ << H(TokHashLiteral) << HS(L"foo") - /* 10 */ << H(TokCondition)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("NOT-quoted-test") - << "!\"foo\"" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokNot) - /* 3 */ << H(TokHashLiteral) << HS(L"foo") - /* 10 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-AND-NOT-test") - << "foo:!bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokNot) - /* 12 */ << H(TokHashLiteral) << HS(L"bar") - /* 19 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-assignment") - << "foo\nVAR=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokLine) << H(2) - /* 12 */ << H(TokHashLiteral) << HS(L"VAR") - /* 19 */ << H(TokAssign) << H(0) - /* 21 */ << H(TokValueTerminator)) - << "" - << true; - - QTest::newRow("test-AND-assignment") - << "foo: VAR =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokBranch) - /* 11 */ /* then branch */ << I(11) - /* 13 */ << H(TokHashLiteral) << HS(L"VAR") - /* 20 */ << H(TokAssign) << H(0) - /* 22 */ << H(TokValueTerminator) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-else-test") - << "foo\nelse: bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokBranch) - /* 11 */ /* then branch */ << I(0) - /* 13 */ /* else branch */ << I(11) - /* 15 */ << H(TokLine) << H(2) - /* 17 */ << H(TokHashLiteral) << HS(L"bar") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("function-else-test") - << "foo()\nelse: bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(0) - /* 14 */ /* else branch */ << I(11) - /* 16 */ << H(TokLine) << H(2) - /* 18 */ << H(TokHashLiteral) << HS(L"bar") - /* 25 */ << H(TokCondition) - /* 26 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-AND-test-else-test") - << "foo:bar\nelse: baz" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokCondition) - /* 19 */ << H(TokBranch) - /* 20 */ /* then branch */ << I(0) - /* 22 */ /* else branch */ << I(11) - /* 24 */ << H(TokLine) << H(2) - /* 26 */ << H(TokHashLiteral) << HS(L"baz") - /* 33 */ << H(TokCondition) - /* 34 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-AND-test-else-test-else-test-function") - << "foo:bar\nelse: baz\nelse: bak\nbuzz()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokCondition) - /* 19 */ << H(TokBranch) - /* 20 */ /* then branch */ << I(0) - /* 22 */ /* else branch */ << I(27) - /* 24 */ << H(TokLine) << H(2) - /* 26 */ << H(TokHashLiteral) << HS(L"baz") - /* 33 */ << H(TokCondition) - /* 34 */ << H(TokBranch) - /* 35 */ /* then branch */ << I(0) - /* 37 */ /* else branch */ << I(11) - /* 39 */ << H(TokLine) << H(3) - /* 41 */ << H(TokHashLiteral) << HS(L"bak") - /* 48 */ << H(TokCondition) - /* 49 */ << H(TokTerminator) - /* 50 */ << H(TokTerminator) - /* 51 */ << H(TokLine) << H(4) - /* 53 */ << H(TokHashLiteral) << HS(L"buzz") - /* 61 */ << H(TokTestCall) - /* 62 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("test-assignment-else-assignment") - << "foo: VAR =\nelse: VAR=" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokBranch) - /* 11 */ /* then branch */ << I(11) - /* 13 */ << H(TokHashLiteral) << HS(L"VAR") - /* 20 */ << H(TokAssign) << H(0) - /* 22 */ << H(TokValueTerminator) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(13) - /* 26 */ << H(TokLine) << H(2) - /* 28 */ << H(TokHashLiteral) << HS(L"VAR") - /* 35 */ << H(TokAssign) << H(0) - /* 37 */ << H(TokValueTerminator) - /* 38 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-else-test-assignment") - << "foo\nelse: bar: VAR =" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokBranch) - /* 11 */ /* then branch */ << I(0) - /* 13 */ /* else branch */ << I(27) - /* 15 */ << H(TokLine) << H(2) - /* 17 */ << H(TokHashLiteral) << HS(L"bar") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokBranch) - /* 26 */ /* then branch */ << I(11) - /* 28 */ << H(TokHashLiteral) << HS(L"VAR") - /* 35 */ << H(TokAssign) << H(0) - /* 37 */ << H(TokValueTerminator) - /* 38 */ << H(TokTerminator) - /* 39 */ /* else branch */ << I(0) - /* 41 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("one function") - << "foo()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("one function (with spaces)") - << " foo( ) " - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("unterminated function call") - << "foo(\nfoo" - << TS() - << "in:1: Missing closing parenthesis in function call" - << false; - - QTest::newRow("function with arguments") - << "foo(blah, hi ho)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah") - /* 16 */ << H(TokArgSeparator) - /* 17 */ << H(TokLiteral | TokNewStr) << S(L"hi") - /* 21 */ << H(TokLiteral | TokNewStr) << S(L"ho") - /* 25 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("function with empty arguments") - << "foo(,)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokArgSeparator) - /* 11 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("function with funny arguments") - << "foo(blah\\, \"hi , \\ho\" ,uh\\ ,\\oh ,, )" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokLiteral | TokNewStr) << S(L"blah\\") - /* 17 */ << H(TokArgSeparator) - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi , \\ho") - /* 29 */ << H(TokArgSeparator) - /* 30 */ << H(TokLiteral | TokNewStr) << S(L"uh\\") - /* 35 */ << H(TokArgSeparator) - /* 36 */ << H(TokLiteral | TokNewStr) << S(L"\\oh") - /* 41 */ << H(TokArgSeparator) - /* 42 */ << H(TokArgSeparator) - /* 43 */ << H(TokFuncTerminator)) - << "WARNING: in:1: Unescaped backslashes are deprecated\n" - "WARNING: in:1: Unescaped backslashes are deprecated\n" - "WARNING: in:1: Unescaped backslashes are deprecated\n" - "WARNING: in:1: Unescaped backslashes are deprecated" - << true; - - QTest::newRow("function with nested call") - << "foo($$blah(hi ho))" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncName | TokNewStr) << HS(L"blah") - /* 18 */ << H(TokLiteral | TokNewStr) << S(L"hi") - /* 22 */ << H(TokLiteral | TokNewStr) << S(L"ho") - /* 26 */ << H(TokFuncTerminator) - /* 27 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("stand-alone parentheses") - << "()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestCall) - /* 3 */ << H(TokFuncTerminator)) - << "in:1: Opening parenthesis without prior test name." - << false; - - QTest::newRow("bogus test and function") - << "foo bar()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestCall) - /* 3 */ << H(TokFuncTerminator)) - << "in:1: Extra characters after test expression." - << false; - - // This is a rather questionable "feature" - QTest::newRow("two functions") - << "foo() bar()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokTestCall) - /* 19 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("function-AND-test") - << "foo():bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokTestCall) - /* 10 */ << H(TokFuncTerminator) - /* 11 */ << H(TokAnd) - /* 12 */ << H(TokHashLiteral) << HS(L"bar") - /* 19 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-AND-function") - << "foo:bar()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokHashLiteral) << HS(L"bar") - /* 18 */ << H(TokTestCall) - /* 19 */ << H(TokFuncTerminator)) - << "" - << true; - - QTest::newRow("NOT-function-AND-test") - << "!foo():bar" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokNot) - /* 3 */ << H(TokHashLiteral) << HS(L"foo") - /* 10 */ << H(TokTestCall) - /* 11 */ << H(TokFuncTerminator) - /* 12 */ << H(TokAnd) - /* 13 */ << H(TokHashLiteral) << HS(L"bar") - /* 20 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("test-AND-NOT-function") - << "foo:!bar()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"foo") - /* 9 */ << H(TokCondition) - /* 10 */ << H(TokAnd) - /* 11 */ << H(TokNot) - /* 12 */ << H(TokHashLiteral) << HS(L"bar") - /* 19 */ << H(TokTestCall) - /* 20 */ << H(TokFuncTerminator)) - << "" - << true; - - // Control statements - - QTest::newRow("for(VAR, LIST) loop") - << "for(VAR, LIST)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"VAR") - /* 9 */ /* iterator */ << I(7) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"LIST") - /* 17 */ << H(TokValueTerminator) - /* 18 */ /* body */ << I(1) - /* 20 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("for(ever) loop") - << "for(ever)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(1) - /* 19 */ << H(TokTerminator)) - << "" - << true; - - // This is a rather questionable "feature" - QTest::newRow("for($$blub) loop") - << "for($$blub)" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokVariable | TokNewStr) << HS(L"blub") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(1) - /* 19 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-for-test-else-test") - << "true:for(VAR, LIST): true\nelse: true" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(31) - /* 14 */ << H(TokForLoop) << HS(L"VAR") - /* 21 */ /* iterator */ << I(7) - /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") - /* 29 */ << H(TokValueTerminator) - /* 30 */ /* body */ << I(12) - /* 32 */ << H(TokLine) << H(1) - /* 34 */ << H(TokHashLiteral) << HS(L"true") - /* 42 */ << H(TokCondition) - /* 43 */ << H(TokTerminator) - /* 44 */ << H(TokTerminator) - /* 45 */ /* else branch */ << I(12) - /* 47 */ << H(TokLine) << H(2) - /* 49 */ << H(TokHashLiteral) << HS(L"true") - /* 57 */ << H(TokCondition) - /* 58 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("next()") - << "for(ever): next()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(4) - /* 19 */ << H(TokLine) << H(1) - /* 21 */ << H(TokNext) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("break()") - << "for(ever): break()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(4) - /* 19 */ << H(TokLine) << H(1) - /* 21 */ << H(TokBreak) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("top-level return()") - << "return()" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokReturn)) - << "" - << true; - - QTest::newRow("else") - << "else" - << TS() - << "in:1: Unexpected 'else'." - << false; - - QTest::newRow("test-{else}") - << "test { else }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(0)) - << "in:1: Unexpected 'else'." - << false; - - QTest::newRow("defineTest-{else}") - << "defineTest(fn) { else }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"fn") - /* 8 */ /* body */ << I(1) - /* 10 */ << H(TokTerminator)) - << "in:1: Unexpected 'else'." - << false; - - QTest::newRow("for-else") - << "for(ever) { else }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(1) - /* 19 */ << H(TokTerminator)) - << "in:1: Unexpected 'else'." - << false; - - // Braces - - QTest::newRow("{}") - << "{ }" - << TS() - << "" - << true; - - QTest::newRow("{}-newlines") - << "\n\n{ }\n\n" - << TS() - << "" - << true; - - QTest::newRow("{") - << "{" - << TS() - << "in:2: Missing closing brace(s)." - << false; - - QTest::newRow("test {") - << "test {" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(0)) - << "in:2: Missing closing brace(s)." - << false; - - QTest::newRow("}") - << "}" - << TS() - << "in:1: Excess closing brace." - << false; - - QTest::newRow("{test}") - << "{ true }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("{test-newlines}") - << "{\ntrue\n}" - << TS( - /* 0 */ << H(TokLine) << H(2) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("{assignment-test}-test") - << "{ VAR = { foo } bar } true" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(4) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{") - /* 14 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 19 */ << H(TokLiteral | TokNewStr) << S(L"}") - /* 22 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 27 */ << H(TokValueTerminator) - /* 28 */ << H(TokHashLiteral) << HS(L"true") - /* 36 */ << H(TokCondition)) - << "" - << true; - - QTest::newRow("assignment with excess opening brace") - << "VAR = { { foo }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"VAR") - /* 9 */ << H(TokAssign) << H(4) - /* 11 */ << H(TokLiteral | TokNewStr) << S(L"{") - /* 14 */ << H(TokLiteral | TokNewStr) << S(L"{") - /* 17 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 22 */ << H(TokLiteral | TokNewStr) << S(L"}") - /* 25 */ << H(TokValueTerminator)) - << "WARNING: in:1: Possible braces mismatch" - << true; - - QTest::newRow("test-{}") - << "true {}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{newlines}") - << "true {\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{test}") - << "true { true }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(10) - /* 14 */ << H(TokHashLiteral) << HS(L"true") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test:-{test}") - << "true: { true }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(10) - /* 14 */ << H(TokHashLiteral) << HS(L"true") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "WARNING: in:1: Excess colon in front of opening brace." - << true; - - QTest::newRow("test-{test-newlines}") - << "true {\ntrue\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(12) - /* 14 */ << H(TokLine) << H(2) - /* 16 */ << H(TokHashLiteral) << HS(L"true") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokTerminator) - /* 26 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test:-{test-newlines}") - << "true: {\ntrue\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(12) - /* 14 */ << H(TokLine) << H(2) - /* 16 */ << H(TokHashLiteral) << HS(L"true") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokTerminator) - /* 26 */ /* else branch */ << I(0)) - << "WARNING: in:1: Excess colon in front of opening brace." - << true; - - QTest::newRow("test-{assignment}") - << "true { VAR = {foo} }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(18) - /* 14 */ << H(TokHashLiteral) << HS(L"VAR") - /* 21 */ << H(TokAssign) << H(0) - /* 23 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") - /* 30 */ << H(TokValueTerminator) - /* 31 */ << H(TokTerminator) - /* 32 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{test-assignment}") - << "true { true: VAR = {foo} }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(33) - /* 14 */ << H(TokHashLiteral) << HS(L"true") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokBranch) - /* 24 */ /* then branch */ << I(18) - /* 26 */ << H(TokHashLiteral) << HS(L"VAR") - /* 33 */ << H(TokAssign) << H(0) - /* 35 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") - /* 42 */ << H(TokValueTerminator) - /* 43 */ << H(TokTerminator) - /* 44 */ /* else branch */ << I(0) - /* 46 */ << H(TokTerminator) - /* 47 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{assignment-newlines}") - << "true {\nVAR = {foo}\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(20) - /* 14 */ << H(TokLine) << H(2) - /* 16 */ << H(TokHashLiteral) << HS(L"VAR") - /* 23 */ << H(TokAssign) << H(0) - /* 25 */ << H(TokLiteral | TokNewStr) << S(L"{foo}") - /* 32 */ << H(TokValueTerminator) - /* 33 */ << H(TokTerminator) - /* 34 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-{}-else-test-{}") - << "true {} else: true {}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(18) - /* 17 */ << H(TokLine) << H(1) - /* 19 */ << H(TokHashLiteral) << HS(L"true") - /* 27 */ << H(TokCondition) - /* 28 */ << H(TokBranch) - /* 29 */ /* then branch */ << I(1) - /* 31 */ << H(TokTerminator) - /* 32 */ /* else branch */ << I(0) - /* 34 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-{}-else-test-{}-newlines") - << "true {\n}\nelse: true {\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(1) - /* 14 */ << H(TokTerminator) - /* 15 */ /* else branch */ << I(18) - /* 17 */ << H(TokLine) << H(3) - /* 19 */ << H(TokHashLiteral) << HS(L"true") - /* 27 */ << H(TokCondition) - /* 28 */ << H(TokBranch) - /* 29 */ /* then branch */ << I(1) - /* 31 */ << H(TokTerminator) - /* 32 */ /* else branch */ << I(0) - /* 34 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-{test}-else-test-{}-newlines") - << "true {\ntrue\n}\nelse: true {\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(12) - /* 14 */ << H(TokLine) << H(2) - /* 16 */ << H(TokHashLiteral) << HS(L"true") - /* 24 */ << H(TokCondition) - /* 25 */ << H(TokTerminator) - /* 26 */ /* else branch */ << I(18) - /* 28 */ << H(TokLine) << H(4) - /* 30 */ << H(TokHashLiteral) << HS(L"true") - /* 38 */ << H(TokCondition) - /* 39 */ << H(TokBranch) - /* 40 */ /* then branch */ << I(1) - /* 42 */ << H(TokTerminator) - /* 43 */ /* else branch */ << I(0) - /* 45 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("for-{next}") - << "for(ever) { next() }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(4) - /* 19 */ << H(TokLine) << H(1) - /* 21 */ << H(TokNext) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("for:-{next}") - << "for(ever): { next() }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokForLoop) << HS(L"") - /* 6 */ /* iterator */ << I(9) - /* 8 */ << H(TokHashLiteral) << HS(L"ever") - /* 16 */ << H(TokValueTerminator) - /* 17 */ /* body */ << I(4) - /* 19 */ << H(TokLine) << H(1) - /* 21 */ << H(TokNext) - /* 22 */ << H(TokTerminator)) - << "WARNING: in:1: Excess colon in front of opening brace." - << true; - - QTest::newRow("test-for-{test-else-test-newlines}") - << "true:for(VAR, LIST) {\ntrue\nelse: true\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(48) - /* 14 */ << H(TokForLoop) << HS(L"VAR") - /* 21 */ /* iterator */ << I(7) - /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") - /* 29 */ << H(TokValueTerminator) - /* 30 */ /* body */ << I(29) - /* 32 */ << H(TokLine) << H(2) - /* 34 */ << H(TokHashLiteral) << HS(L"true") - /* 42 */ << H(TokCondition) - /* 43 */ << H(TokBranch) - /* 44 */ /* then branch */ << I(0) - /* 46 */ /* else branch */ << I(12) - /* 48 */ << H(TokLine) << H(3) - /* 50 */ << H(TokHashLiteral) << HS(L"true") - /* 58 */ << H(TokCondition) - /* 59 */ << H(TokTerminator) - /* 60 */ << H(TokTerminator) - /* 61 */ << H(TokTerminator) - /* 62 */ /* else branch */ << I(0)) - << "" - << true; - - QTest::newRow("test-for-{test-else-test}") - << "true:for(VAR, LIST) { true\nelse: true }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"true") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(48) - /* 14 */ << H(TokForLoop) << HS(L"VAR") - /* 21 */ /* iterator */ << I(7) - /* 23 */ << H(TokLiteral | TokNewStr) << S(L"LIST") - /* 29 */ << H(TokValueTerminator) - /* 30 */ /* body */ << I(29) - /* 32 */ << H(TokLine) << H(1) - /* 34 */ << H(TokHashLiteral) << HS(L"true") - /* 42 */ << H(TokCondition) - /* 43 */ << H(TokBranch) - /* 44 */ /* then branch */ << I(0) - /* 46 */ /* else branch */ << I(12) - /* 48 */ << H(TokLine) << H(2) - /* 50 */ << H(TokHashLiteral) << HS(L"true") - /* 58 */ << H(TokCondition) - /* 59 */ << H(TokTerminator) - /* 60 */ << H(TokTerminator) - /* 61 */ << H(TokTerminator) - /* 62 */ /* else branch */ << I(0)) - << "" - << true; - - // Custom functions - - QTest::newRow("defineTest-{newlines}") - << "defineTest(test) {\n}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"test") - /* 10 */ /* body */ << I(1) - /* 12 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("defineTest:-test") - << "defineTest(test): test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"test") - /* 10 */ /* body */ << I(12) - /* 12 */ << H(TokLine) << H(1) - /* 14 */ << H(TokHashLiteral) << HS(L"test") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("defineTest-{test}") - << "defineTest(test) { test }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"test") - /* 10 */ /* body */ << I(12) - /* 12 */ << H(TokLine) << H(1) - /* 14 */ << H(TokHashLiteral) << HS(L"test") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("defineTest-{return}") - << "defineTest(test) { return() }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokTestDef) << HS(L"test") - /* 10 */ /* body */ << I(4) - /* 12 */ << H(TokLine) << H(1) - /* 14 */ << H(TokReturn) - /* 15 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("defineReplace-{return-stuff}") - << "defineReplace(stuff) { return(foo bar) }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokReplaceDef) << HS(L"stuff") - /* 11 */ /* body */ << I(14) - /* 13 */ << H(TokLine) << H(1) - /* 15 */ << H(TokLiteral | TokNewStr) << S(L"foo") - /* 20 */ << H(TokLiteral | TokNewStr) << S(L"bar") - /* 25 */ << H(TokReturn) - /* 26 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-AND-defineTest-{}") - << "test: defineTest(test) {}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokAnd) - /* 12 */ << H(TokTestDef) << HS(L"test") - /* 20 */ /* body */ << I(1) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - QTest::newRow("test-OR-defineTest-{}") - << "test| defineTest(test) {}" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokOr) - /* 12 */ << H(TokTestDef) << HS(L"test") - /* 20 */ /* body */ << I(1) - /* 22 */ << H(TokTerminator)) - << "" - << true; - - // Operator abuse - - QTest::newRow("!") - << "" - << TS() - << "" - << true; - - QTest::newRow("|") - << "" - << TS() - << "" - << true; - - QTest::newRow(":") - << "" - << TS() - << "" - << true; - - QTest::newRow("NOT-assignment") - << "!VAR =" - << TS() - << "in:1: Unexpected NOT operator in front of assignment." - << false; - - QTest::newRow("NOT-{}") - << "!{}" - << TS() - << "in:1: Unexpected NOT operator in front of opening brace." - << false; - - QTest::newRow("NOT-else") - << "test\n!else {}" - << TS() - << "in:2: Unexpected NOT operator in front of else." - << false; - - QTest::newRow("NOT-for-{}") - << "!for(ever) {}" - << TS() - << "in:1: Unexpected NOT operator in front of for()." - << false; - - QTest::newRow("NOT-defineTest-{}") - << "!defineTest(test) {}" - << TS() - << "in:1: Unexpected NOT operator in front of function definition." - << false; - - QTest::newRow("AND-test") - << ":test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition)) - << "in:1: AND operator without prior condition." - << false; - - QTest::newRow("test-AND-else") - << "test:else" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition)) - << "in:1: Unexpected AND operator in front of else." - << false; - - QTest::newRow("test-AND-AND-test") - << "test::test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokAnd) - /* 12 */ << H(TokHashLiteral) << HS(L"test") - /* 20 */ << H(TokCondition)) - << "WARNING: in:1: Stray AND operator in front of AND operator." - << true; - - QTest::newRow("test-AND-OR-test") - << "test:|test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokOr) - /* 12 */ << H(TokHashLiteral) << HS(L"test") - /* 20 */ << H(TokCondition)) - << "WARNING: in:1: Stray AND operator in front of OR operator." - << true; - - QTest::newRow("test-{AND-test}") - << "test { :test }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(10) - /* 14 */ << H(TokHashLiteral) << HS(L"test") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "in:1: AND operator without prior condition." - << false; - - QTest::newRow("test-OR-assignment") - << "foo| VAR =" - << TS() - << "in:1: Unexpected OR operator in front of assignment." - << false; - - QTest::newRow("test-OR-{}") - << "foo|{}" - << TS() - << "in:1: Unexpected OR operator in front of opening brace." - << false; - - QTest::newRow("test-OR-for") - << "foo|for(ever) {}" - << TS() - << "in:1: Unexpected OR operator in front of for()." - << false; - - QTest::newRow("OR-test") - << "|test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition)) - << "in:1: OR operator without prior condition." - << false; - - QTest::newRow("test-OR-else") - << "test|else" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition)) - << "in:1: Unexpected OR operator in front of else." - << false; - - QTest::newRow("test-OR-OR-test") - << "test||test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokOr) - /* 12 */ << H(TokHashLiteral) << HS(L"test") - /* 20 */ << H(TokCondition)) - << "WARNING: in:1: Stray OR operator in front of OR operator." - << true; - - QTest::newRow("test-OR-AND-test") - << "test|:test" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokAnd) - /* 12 */ << H(TokHashLiteral) << HS(L"test") - /* 20 */ << H(TokCondition)) - << "WARNING: in:1: Stray OR operator in front of AND operator." - << true; - - QTest::newRow("test-{OR-test}") - << "test { |test }" - << TS( - /* 0 */ << H(TokLine) << H(1) - /* 2 */ << H(TokHashLiteral) << HS(L"test") - /* 10 */ << H(TokCondition) - /* 11 */ << H(TokBranch) - /* 12 */ /* then branch */ << I(10) - /* 14 */ << H(TokHashLiteral) << HS(L"test") - /* 22 */ << H(TokCondition) - /* 23 */ << H(TokTerminator) - /* 24 */ /* else branch */ << I(0)) - << "in:1: OR operator without prior condition." - << false; - - // option() (these produce no tokens) - - QTest::newRow("option(host_build)") - << "option(host_build)" - << TS() - << "" - << true; - - QTest::newRow("option()") - << "option()" - << TS() - << "in:1: option() requires one literal argument." - << false; - - QTest::newRow("option(host_build magic)") - << "option(host_build magic)" - << TS() - << "in:1: option() requires one literal argument." - << false; - - QTest::newRow("option(host_build, magic)") - << "option(host_build, magic)" - << TS() - << "in:1: option() requires one literal argument." - << false; - - QTest::newRow("option($$OPTION)") - << "option($$OPTION)" - << TS() - << "in:1: option() requires one literal argument." - << false; - - QTest::newRow("{option(host_build)}") - << "{option(host_build)}" - << TS() - << "in:1: option() must appear outside any control structures." - << false; + QString pfx = ((type & QMakeParserHandler::CategoryMask) == QMakeParserHandler::WarningMessage) + ? QString::fromLatin1("WARNING: ") : QString(); + if (lineNo) + doPrint(QStringLiteral("%1%2:%3: %4").arg(pfx, fileName, QString::number(lineNo), msg)); + else + doPrint(QStringLiteral("%1%2").arg(pfx, msg)); } -void tst_qmakelib::proParser() +void QMakeTestHandler::doPrint(const QString &msg) { - QFETCH(QString, in); - QFETCH(QString, out); - QFETCH(QString, msgs); - QFETCH(bool, ok); - - bool verified = true; - QMakeHandler handler; - handler.setExpectedMessages(msgs.split('\n', QString::SkipEmptyParts)); - QMakeVfs vfs; - QMakeParser parser(0, &vfs, &handler); - ProFile *pro = parser.parsedProBlock(in, "in", 1, QMakeParser::FullGrammar); - if (handler.printedMessages()) { - qWarning("Got unexpected message(s)"); - verified = false; + if (!expected.isEmpty() && expected.first() == msg) { + expected.removeAt(0); + } else { + qWarning("%s", qPrintable(msg)); + printed = true; } - QStringList missingMsgs = handler.expectedMessages(); - if (!missingMsgs.isEmpty()) { - foreach (const QString &msg, missingMsgs) - qWarning("Missing message: %s", qPrintable(msg)); - verified = false; - } - if (pro->isOk() != ok) { - static const char * const lbl[] = { "failure", "success" }; - qWarning("Expected %s, got %s", lbl[int(ok)], lbl[1 - int(ok)]); - verified = false; - } - if (pro->items() != out && (ok || !out.isEmpty())) { - qWarning("Bytecode mismatch.\nActual:%s\nExpected:%s", - qPrintable(QMakeParser::formatProBlock(pro->items())), - qPrintable(QMakeParser::formatProBlock(out))); - verified = false; - } - pro->deref(); - QVERIFY(verified); } QTEST_MAIN(tst_qmakelib) -#include "tst_qmakelib.moc" diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.h b/tests/auto/tools/qmakelib/tst_qmakelib.h new file mode 100644 index 0000000000..c4716ca65e --- /dev/null +++ b/tests/auto/tools/qmakelib/tst_qmakelib.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include +#include + +class tst_qmakelib : public QObject +{ + Q_OBJECT + +public: + tst_qmakelib() {} + virtual ~tst_qmakelib() {} + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void quoteArgUnix_data(); + void quoteArgUnix(); + void quoteArgWin_data(); + void quoteArgWin(); + void pathUtils(); + + void proString(); + void proStringList(); + + void proParser_data(); + void proParser(); + + void proEval_data(); + void proEval(); + +private: + void addParseOperators(); + void addParseValues(); + void addParseConditions(); + void addParseControlStatements(); + void addParseBraces(); + void addParseCustomFunctions(); + void addParseAbuse(); + + void addAssignments(); + void addExpansions(); + void addControlStructs(); + void addReplaceFunctions(const QString &qindir); + void addTestFunctions(const QString &qindir); + + QProcessEnvironment m_env; + QHash m_prop; + QString m_indir, m_outdir; +}; + +class QMakeTestHandler : public QMakeHandler { +public: + QMakeTestHandler() : QMakeHandler(), printed(false) {} + virtual void message(int type, const QString &msg, const QString &fileName, int lineNo) + { print(fileName, lineNo, type, msg); } + + virtual void fileMessage(const QString &msg) + { doPrint(msg); } + + virtual void aboutToEval(ProFile *, ProFile *, EvalFileType) {} + virtual void doneWithEval(ProFile *) {} + + void setExpectedMessages(const QStringList &msgs) { expected = msgs; } + QStringList expectedMessages() const { return expected; } + + bool printedMessages() const { return printed; } + +private: + void print(const QString &fileName, int lineNo, int type, const QString &msg); + void doPrint(const QString &msg); + + QStringList expected; + bool printed; +}; + diff --git a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp index fecc14f541..e62ce3ceb5 100644 --- a/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp +++ b/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp @@ -564,6 +564,11 @@ void tst_QDialog::snapToDefaultButton() topLeftPos = QPoint(topLeftPos.x() + 100, topLeftPos.y() + 100); QPoint startingPos(topLeftPos.x() + 250, topLeftPos.y() + 250); QCursor::setPos(startingPos); +#ifdef Q_OS_OSX + // On OS X we use CGEventPost to move the cursor, it needs at least + // some time before the event handled and the position really set. + QTest::qWait(100); +#endif QCOMPARE(QCursor::pos(), startingPos); QDialog dialog; QPushButton *button = new QPushButton(&dialog); diff --git a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp index da0c5532a5..9b92c34fb5 100644 --- a/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicswidget/tst_qgraphicswidget.cpp @@ -179,6 +179,7 @@ private slots: void task250119_shortcutContext(); void QT_BUG_6544_tabFocusFirstUnsetWhenRemovingItems(); void QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems(); + void QTBUG_45867_send_itemChildAddedChange_to_parent(); }; @@ -3490,5 +3491,36 @@ void tst_QGraphicsWidget::QT_BUG_12056_tabFocusFirstUnsetWhenRemovingItems() //This should not crash } +void tst_QGraphicsWidget::QTBUG_45867_send_itemChildAddedChange_to_parent() +{ + class GraphicsItem : public QGraphicsItem + { + public: + int m_itemChildAddedChangeNotificationsCount; + + GraphicsItem() + : QGraphicsItem(), + m_itemChildAddedChangeNotificationsCount(0) + { + } + + QRectF boundingRect() const Q_DECL_OVERRIDE { return QRectF(); } + + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) Q_DECL_OVERRIDE {} + + protected: + QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) Q_DECL_OVERRIDE + { + if (change == QGraphicsItem::ItemChildAddedChange) + ++m_itemChildAddedChangeNotificationsCount; + return QGraphicsItem::itemChange(change, value); + } + }; + + GraphicsItem item; + QGraphicsWidget widget(&item); + QCOMPARE(item.m_itemChildAddedChangeNotificationsCount, 1); +} + QTEST_MAIN(tst_QGraphicsWidget) #include "tst_qgraphicswidget.moc" diff --git a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp index 22245707cc..9b8b306e00 100644 --- a/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp +++ b/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #if defined(Q_OS_WIN) || defined(Q_OS_WINCE) # include @@ -2350,11 +2351,34 @@ void tst_QListView::testViewOptions() QCOMPARE(options.decorationPosition, QStyleOptionViewItem::Top); } +// make sure we have no transient scroll bars +class TempStyleSetter +{ +public: + TempStyleSetter() + : m_oldStyle(qApp->style()) + { + m_oldStyle->setParent(0); + QListView tempView; + if (QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, tempView.horizontalScrollBar())) + QApplication::setStyle(QStyleFactory::create("Fusion")); + } + + ~TempStyleSetter() + { + QApplication::setStyle(m_oldStyle); + } +private: + QStyle* m_oldStyle; +}; + void tst_QListView::taskQTBUG_39902_mutualScrollBars() { QWidget window; window.resize(400, 300); QListView *view = new QListView(&window); + // make sure we have no transient scroll bars + TempStyleSetter styleSetter; QStandardItemModel model(200, 1); const QSize itemSize(100, 20); for (int i = 0; i < model.rowCount(); ++i) @@ -2372,6 +2396,44 @@ void tst_QListView::taskQTBUG_39902_mutualScrollBars() view->resize(itemSize.width() + view->frameWidth() * 2, model.rowCount() * itemSize.height() + view->frameWidth() * 2); // this will end up in a stack overflow, if QTBUG-39902 is not fixed QTest::qWait(100); + + // these tests do not apply with transient scroll bars enabled + QVERIFY (!view->style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, view->horizontalScrollBar())); + + // make it double as large, no scroll bars should be visible + view->resize((itemSize.width() + view->frameWidth() * 2) * 2, (model.rowCount() * itemSize.height() + view->frameWidth() * 2) * 2); + QTRY_VERIFY(!view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(!view->verticalScrollBar()->isVisible()); + + // make it half the size, both scroll bars should be visible + view->resize((itemSize.width() + view->frameWidth() * 2) / 2, (model.rowCount() * itemSize.height() + view->frameWidth() * 2) / 2); + QTRY_VERIFY(view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(view->verticalScrollBar()->isVisible()); + + // make it double as large, no scroll bars should be visible + view->resize((itemSize.width() + view->frameWidth() * 2) * 2, (model.rowCount() * itemSize.height() + view->frameWidth() * 2) * 2); + QTRY_VERIFY(!view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(!view->verticalScrollBar()->isVisible()); + + // now, coming from the double size, resize it to the exactly matching size, still no scroll bars should be visible again + view->resize(itemSize.width() + view->frameWidth() * 2, model.rowCount() * itemSize.height() + view->frameWidth() * 2); + QTRY_VERIFY(!view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(!view->verticalScrollBar()->isVisible()); + + // now remove just one single pixel in height -> both scroll bars will show up since they depend on each other + view->resize(itemSize.width() + view->frameWidth() * 2, model.rowCount() * itemSize.height() + view->frameWidth() * 2 - 1); + QTRY_VERIFY(view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(view->verticalScrollBar()->isVisible()); + + // now remove just one single pixel in with -> both scroll bars will show up since they depend on each other + view->resize(itemSize.width() + view->frameWidth() * 2 - 1, model.rowCount() * itemSize.height() + view->frameWidth() * 2); + QTRY_VERIFY(view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(view->verticalScrollBar()->isVisible()); + + // finally, coming from a size being to small, resize back to the exactly matching size -> both scroll bars should disappear again + view->resize(itemSize.width() + view->frameWidth() * 2, model.rowCount() * itemSize.height() + view->frameWidth() * 2); + QTRY_VERIFY(!view->horizontalScrollBar()->isVisible()); + QTRY_VERIFY(!view->verticalScrollBar()->isVisible()); } void tst_QListView::horizontalScrollingByVerticalWheelEvents() diff --git a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp index 6786ae9aa2..dcbdbe824a 100644 --- a/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp +++ b/tests/auto/widgets/itemviews/qlistwidget/tst_qlistwidget.cpp @@ -605,21 +605,21 @@ void tst_QListWidget::insertItems() void tst_QListWidget::itemAssignment() { QListWidgetItem itemInWidget("inWidget", testWidget); - itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsTristate); + itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsUserTristate); QListWidgetItem itemOutsideWidget("outsideWidget"); QVERIFY(itemInWidget.listWidget()); QCOMPARE(itemInWidget.text(), QString("inWidget")); - QVERIFY(itemInWidget.flags() & Qt::ItemIsTristate); + QVERIFY(itemInWidget.flags() & Qt::ItemIsUserTristate); QVERIFY(!itemOutsideWidget.listWidget()); QCOMPARE(itemOutsideWidget.text(), QString("outsideWidget")); - QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsTristate)); + QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsUserTristate)); itemOutsideWidget = itemInWidget; QVERIFY(!itemOutsideWidget.listWidget()); QCOMPARE(itemOutsideWidget.text(), QString("inWidget")); - QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsTristate); + QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsUserTristate); } void tst_QListWidget::item_data() diff --git a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp index a4c6e13979..36bc23910c 100644 --- a/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp +++ b/tests/auto/widgets/itemviews/qtablewidget/tst_qtablewidget.cpp @@ -281,21 +281,21 @@ void tst_QTableWidget::itemAssignment() { QTableWidgetItem itemInWidget("inWidget"); testWidget->setItem(0, 0, &itemInWidget); - itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsTristate); + itemInWidget.setFlags(itemInWidget.flags() | Qt::ItemIsUserTristate); QTableWidgetItem itemOutsideWidget("outsideWidget"); QVERIFY(itemInWidget.tableWidget()); QCOMPARE(itemInWidget.text(), QString("inWidget")); - QVERIFY(itemInWidget.flags() & Qt::ItemIsTristate); + QVERIFY(itemInWidget.flags() & Qt::ItemIsUserTristate); QVERIFY(!itemOutsideWidget.tableWidget()); QCOMPARE(itemOutsideWidget.text(), QString("outsideWidget")); - QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsTristate)); + QVERIFY(!(itemOutsideWidget.flags() & Qt::ItemIsUserTristate)); itemOutsideWidget = itemInWidget; QVERIFY(!itemOutsideWidget.tableWidget()); QCOMPARE(itemOutsideWidget.text(), QString("inWidget")); - QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsTristate); + QVERIFY(itemOutsideWidget.flags() & Qt::ItemIsUserTristate); } void tst_QTableWidget::item_data() diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index 3ead172d82..1324027af6 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -255,6 +255,7 @@ private slots: void taskQTBUG_8176_emitOnExpandAll(); void taskQTBUG_34717_collapseAtBottom(); void taskQTBUG_37813_crash(); + void taskQTBUG_45697_crash(); void testInitialFocus(); }; @@ -4385,5 +4386,82 @@ void tst_QTreeView::taskQTBUG_37813_crash() #endif // QT_BUILD_INTERNAL } +// QTBUG-45697: Using a QTreeView with a multi-column model filtered by QSortFilterProxyModel, +// when sorting the source model while the widget is not yet visible and showing the widget +// later on, corruption occurs in QTreeView. +class Qtbug45697TestWidget : public QWidget +{ + Q_OBJECT +public: + static const int columnCount = 3; + + explicit Qtbug45697TestWidget(); + int timerTick() const { return m_timerTick; } + +public slots: + void slotTimer(); + +private: + QTreeView *m_treeView; + QStandardItemModel *m_model; + QSortFilterProxyModel *m_sortFilterProxyModel; + int m_timerTick; +}; + +Qtbug45697TestWidget::Qtbug45697TestWidget() + : m_treeView(new QTreeView(this)) + , m_model(new QStandardItemModel(0, Qtbug45697TestWidget::columnCount, this)) + , m_sortFilterProxyModel(new QSortFilterProxyModel(this)) + , m_timerTick(0) + { + QVBoxLayout *vBoxLayout = new QVBoxLayout(this); + vBoxLayout->addWidget(m_treeView); + + for (char sortChar = 'z'; sortChar >= 'a' ; --sortChar) { + QList items; + for (int column = 0; column < Qtbug45697TestWidget::columnCount; ++column) { + const QString text = QLatin1Char(sortChar) + QLatin1String(" ") + QString::number(column); + items.append(new QStandardItem(text)); + } + m_model->appendRow(items); + } + + m_sortFilterProxyModel->setSourceModel(m_model); + m_treeView->setModel(m_sortFilterProxyModel); + + QHeaderView *headerView = m_treeView->header(); + for (int s = 1, lastSection = headerView->count() - 1; s < lastSection; ++s ) + headerView->setSectionResizeMode(s, QHeaderView::ResizeToContents); + + QTimer *timer = new QTimer(this); + timer->setInterval(50); + connect(timer, &QTimer::timeout, this, &Qtbug45697TestWidget::slotTimer); + timer->start(); +} + +void Qtbug45697TestWidget::slotTimer() +{ + switch (m_timerTick++) { + case 0: + m_model->sort(0); + break; + case 1: + show(); + break; + default: + close(); + break; + } +} + +void tst_QTreeView::taskQTBUG_45697_crash() +{ + Qtbug45697TestWidget testWidget; + testWidget.setWindowTitle(QTest::currentTestFunction()); + testWidget.resize(400, 400); + testWidget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(100, 100)); + QTRY_VERIFY(testWidget.timerTick() >= 2); +} + QTEST_MAIN(tst_QTreeView) #include "tst_qtreeview.moc" diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp index c9a1a64135..c33fd5a951 100644 --- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -178,6 +178,12 @@ private slots: void settableStyleHints_data(); void settableStyleHints(); // Needs to run last as it changes style hints. + +protected slots: + void quitApplication(); + +private: + bool quitApplicationTriggered; }; class EventSpy : public QObject @@ -235,6 +241,7 @@ public: static char *argv0; tst_QApplication::tst_QApplication() + : quitApplicationTriggered(false) { #ifdef Q_OS_WINCE // Clean up environment previously to launching test @@ -719,11 +726,8 @@ void tst_QApplication::quitOnLastWindowClosed() { int argc = 0; QApplication app(argc, 0); - QTimer timer; - timer.setInterval(100); QSignalSpy spy(&app, SIGNAL(aboutToQuit())); - QSignalSpy spy2(&timer, SIGNAL(timeout())); CloseEventTestWindow mainWindow; @@ -733,14 +737,14 @@ void tst_QApplication::quitOnLastWindowClosed() mainWindow.show(); QVERIFY(QTest::qWaitForWindowExposed(&mainWindow)); - timer.start(); - QTimer::singleShot(1000, &mainWindow, SLOT(close())); // This should quit the application - QTimer::singleShot(2000, &app, SLOT(quit())); // This makes sure we quit even if it didn't + QTimer::singleShot(1000, &mainWindow, SLOT(close())); // This should NOT quit the application (see CloseEventTestWindow) + quitApplicationTriggered = false; + QTimer::singleShot(2000, this, SLOT(quitApplication())); // This actually quits the application. app.exec(); QCOMPARE(spy.count(), 1); - QVERIFY(spy2.count() > 15); // Should be around 20 if closing did not caused the quit + QVERIFY(quitApplicationTriggered); } { int argc = 0; @@ -768,24 +772,20 @@ void tst_QApplication::quitOnLastWindowClosed() QApplication app(argc, 0); QVERIFY(app.quitOnLastWindowClosed()); - QTimer timer; - timer.setInterval(100); - QSignalSpy timerSpy(&timer, SIGNAL(timeout())); - QWindow w; w.show(); QWidget wid; wid.show(); - timer.start(); QTimer::singleShot(1000, &wid, SLOT(close())); // This should NOT quit the application because the // QWindow is still there. - QTimer::singleShot(2000, &app, SLOT(quit())); // This causes the quit. + quitApplicationTriggered = false; + QTimer::singleShot(2000, this, SLOT(quitApplication())); // This causes the quit. app.exec(); - QVERIFY(timerSpy.count() > 15); // Should be around 20 if closing did not caused the quit + QVERIFY(quitApplicationTriggered); // Should be around 20 if closing did not caused the quit } { // QTBUG-31569: If the last widget with Qt::WA_QuitOnClose set is closed, other // widgets that don't have the attribute set should be closed automatically. @@ -2406,6 +2406,12 @@ void tst_QApplication::globalStaticObjectDestruction() #endif } +void tst_QApplication::quitApplication() +{ + quitApplicationTriggered = true; + qApp->quit(); +} + //QTEST_APPLESS_MAIN(tst_QApplication) int main(int argc, char *argv[]) { diff --git a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp index ebd99be786..0de9e188a0 100644 --- a/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp +++ b/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp @@ -34,30 +34,32 @@ #include #include +#include +#include class tst_QToolTip : public QObject { Q_OBJECT -public: - tst_QToolTip() {} - virtual ~tst_QToolTip() {} - -public slots: - void initTestCase() {} - void cleanupTestCase() {} - void init() {} - void cleanup() {} - private slots: - - // task-specific tests below me + void init(); + void cleanup(); void task183679_data(); void task183679(); void whatsThis(); void setPalette(); }; +void tst_QToolTip::init() +{ + QVERIFY(!QToolTip::isVisible()); +} + +void tst_QToolTip::cleanup() +{ + QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty()); +} + class Widget_task183679 : public QWidget { Q_OBJECT @@ -100,12 +102,14 @@ void tst_QToolTip::task183679() #endif Widget_task183679 widget; + widget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(50, 50)); + widget.setWindowTitle(QLatin1String(QTest::currentTestFunction()) + + QLatin1Char(' ') + QLatin1String(QTest::currentDataTag())); widget.show(); QApplication::setActiveWindow(&widget); QVERIFY(QTest::qWaitForWindowActive(&widget)); widget.showDelayedToolTip(100); - QTest::qWait(300); QTRY_VERIFY(QToolTip::isVisible()); QTest::keyPress(&widget, key); @@ -116,26 +120,31 @@ void tst_QToolTip::task183679() QTest::qWait(1500); QCOMPARE(QToolTip::isVisible(), visible); + if (visible) + QToolTip::hideText(); } -#include +static QWidget *findWhatsThat() +{ + foreach (QWidget *widget, QApplication::topLevelWidgets()) { + if (widget->inherits("QWhatsThat")) + return widget; + } + return Q_NULLPTR; +} void tst_QToolTip::whatsThis() { qApp->setStyleSheet( "QWidget { font-size: 72px; }" ); - QWhatsThis::showText(QPoint(0,0), "THis is text"); - QTest::qWait(400); - QWidget *whatsthis = 0; - foreach (QWidget *widget, QApplication::topLevelWidgets()) { - if (widget->inherits("QWhatsThat")) { - whatsthis = widget; - break; - } - } - QVERIFY(whatsthis); + QWhatsThis::showText(QPoint(0, 0), "This is text"); + + QWidget *whatsthis = Q_NULLPTR; + QTRY_VERIFY( (whatsthis = findWhatsThat()) ); QVERIFY(whatsthis->isVisible()); - QVERIFY(whatsthis->height() > 100); // Test QTBUG-2416 - qApp->setStyleSheet(""); + const int whatsThisHeight = whatsthis->height(); + qApp->setStyleSheet(QString()); + QWhatsThis::hideText(); + QVERIFY2(whatsThisHeight > 100, QByteArray::number(whatsThisHeight)); // Test QTBUG-2416 } @@ -167,6 +176,7 @@ void tst_QToolTip::setPalette() newPalette.setColor(QPalette::ToolTipText, Qt::blue); QToolTip::setPalette(newPalette); QCOMPARE(toolTip->palette(), newPalette); + QToolTip::hideText(); } QTEST_MAIN(tst_QToolTip) diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index ed40f98051..591aa9e40f 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -1,11 +1,16 @@ +# OSX QTBUG-25300 QTBUG-45502 [normalGeometry] ubuntu-14.04 +osx [saveRestoreGeometry] ubuntu-14.04 +osx [restoreVersion1Geometry] ubuntu-14.04 +osx [updateWhileMinimized] ubuntu-14.04 +osx [focusProxyAndInputMethods] ubuntu-14.04 [touchEventSynthesizedMouseEvent] @@ -14,3 +19,119 @@ ubuntu-14.04 ubuntu-14.04 [largerThanScreen_QTBUG30142] ubuntu-14.04 +[windowState] +osx +[showMaximized] +osx +[setGeometry] +osx +[stackUnder] +osx +[raise] +osx-10.9 +[widgetAt] +osx +[sheetOpacity] +osx +[resizeEvent] +osx +[setWindowGeometry:100,123 200x200, flags 0] +osx-10.10 +[windowMoveResize:100,123 200x200, flags 0] +osx-10.10 +[setWindowGeometry:100,122 200x200, flags 0] +osx-10.9 +[windowMoveResize:100,122 200x200, flags 0] +osx-10.9 +[setWindowGeometry:100,100 824x564, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x564, flags 0] +osx-10.10 +[setWindowGeometry:100,100 824x516, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x516, flags 0] +osx-10.10 +[setWindowGeometry:100,73 200x0, flags 0] +osx-10.10 +[windowMoveResize:100,73 200x0, flags 0] +osx-10.10 +[setWindowGeometry:100,100 824x519, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x519, flags 0] +osx-10.10 +[setWindowGeometry:100,100 824x518, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x518, flags 0] +osx-10.10 +[setWindowGeometry:100,72 200x0, flags 0] +osx-10.9 +[windowMoveResize:100,72 200x0, flags 0] +osx-10.9 +[setWindowGeometry:100,122 952x574, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x574, flags 0] +osx-10.9 +[setWindowGeometry:100,122 952x578, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x578, flags 0] +osx-10.9 +[setWindowGeometry:100,122 952x576, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x576, flags 0] +osx-10.9 +[setWindowGeometry:100,100 824x521, flags 0] +osx-10.10 +[windowMoveResize:100,100 824x521, flags 0] +osx-10.10 +[setWindowGeometry:100,122 952x577, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x577, flags 0] +osx-10.9 +[setWindowGeometry:100,122 952x580, flags 0] +osx-10.9 +[windowMoveResize:100,122 952x580, flags 0] +osx-10.9 +[windowMoveResize:130,72 0x0, flags 0] +osx-10.9 +[windowMoveResize:130,122 0x200, flags 0] +osx-10.9 +[childEvents] +osx +[renderInvisible] +osx +[optimizedResizeMove] +osx +[optimizedResize_topLevel] +osx +[render_systemClip] +osx +[update] +osx +[doubleRepaint] +osx +[childAt_unifiedToolBar] +osx +[showMinimizedKeepsFocus] +osx-10.10 +[moveWindowInShowEvent:1] +osx-10.9 +[moveWindowInShowEvent:2] +osx-10.9 +[taskQTBUG_4055_sendSyntheticEnterLeave] +osx +[syntheticEnterLeave] +osx +[maskedUpdate] +osx +[hideWhenFocusWidgetIsChild] +osx-10.10 +[hideOpaqueChildWhileHidden] +osx +[resizeStaticContentsChildWidget_QTBUG35282] +osx-10.9 +[lower] +osx +[setClearAndResizeMask] +osx +[setToolTip] +osx-10.9 diff --git a/tests/auto/widgets/kernel/qwidget/qwidget.pro b/tests/auto/widgets/kernel/qwidget/qwidget.pro index 30e1048247..aae083d45e 100644 --- a/tests/auto/widgets/kernel/qwidget/qwidget.pro +++ b/tests/auto/widgets/kernel/qwidget/qwidget.pro @@ -21,5 +21,3 @@ x11 { } !wince*:win32:!winrt: LIBS += -luser32 -lgdi32 - -mac:CONFIG+=insignificant_test # QTBUG-25300, QTBUG-23695 diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 10c553bd3e..68ccaef43f 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -436,6 +436,7 @@ private slots: void grabKeyboard(); void touchEventSynthesizedMouseEvent(); + void touchUpdateOnNewTouch(); void styleSheetPropagation(); @@ -3335,8 +3336,6 @@ void tst_QWidget::widgetAt() #if defined(Q_OS_WINCE) QEXPECT_FAIL("", "Windows CE does only support rectangular regions", Continue); //See also task 147191 #endif - if (!QGuiApplication::platformName().compare(QLatin1String("cocoa"), Qt::CaseInsensitive)) - QEXPECT_FAIL("", "Window mask not implemented on Mac QTBUG-22326", Continue); QTRY_VERIFY((wr = QApplication::widgetAt(testPos))); QTRY_COMPARE(wr->objectName(), w1->objectName()); @@ -3355,8 +3354,6 @@ void tst_QWidget::widgetAt() #if defined(Q_OS_WINCE) QEXPECT_FAIL("", "Windows CE does only support rectangular regions", Continue); //See also task 147191 #endif - if (!QGuiApplication::platformName().compare(QLatin1String("cocoa"), Qt::CaseInsensitive)) - QEXPECT_FAIL("", "Window mask not implemented on Mac QTBUG-22326", Continue); QTRY_VERIFY(QApplication::widgetAt(testPos) == w1.data()); QTRY_VERIFY(QApplication::widgetAt(testPos + QPoint(1, 1)) == w2.data()); } @@ -9757,6 +9754,9 @@ class TouchMouseWidget : public QWidget { public: explicit TouchMouseWidget(QWidget *parent = 0) : QWidget(parent), + m_touchBeginCount(0), + m_touchUpdateCount(0), + m_touchEndCount(0), m_touchEventCount(0), m_acceptTouch(false), m_mouseEventCount(0), @@ -9783,6 +9783,12 @@ protected: case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: + if (e->type() == QEvent::TouchBegin) + ++m_touchBeginCount; + else if (e->type() == QEvent::TouchUpdate) + ++m_touchUpdateCount; + else if (e->type() == QEvent::TouchEnd) + ++m_touchEndCount; ++m_touchEventCount; if (m_acceptTouch) e->accept(); @@ -9807,6 +9813,9 @@ protected: } public: + int m_touchBeginCount; + int m_touchUpdateCount; + int m_touchEndCount; int m_touchEventCount; bool m_acceptTouch; int m_mouseEventCount; @@ -9923,6 +9932,46 @@ void tst_QWidget::touchEventSynthesizedMouseEvent() } } +void tst_QWidget::touchUpdateOnNewTouch() +{ + QTouchDevice *device = new QTouchDevice; + device->setType(QTouchDevice::TouchScreen); + QWindowSystemInterface::registerTouchDevice(device); + + TouchMouseWidget widget; + widget.setAcceptTouch(true); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(new QWidget); + widget.setLayout(layout); + widget.show(); + + QWindow* window = widget.windowHandle(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + QCOMPARE(widget.m_touchBeginCount, 0); + QCOMPARE(widget.m_touchUpdateCount, 0); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).press(0, QPoint(20, 20), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 0); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).move(0, QPoint(25, 25), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 1); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).stationary(0).press(1, QPoint(40, 40), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 2); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).stationary(1).release(0, QPoint(25, 25), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 3); + QCOMPARE(widget.m_touchEndCount, 0); + QTest::touchEvent(window, device).release(1, QPoint(40, 40), window); + QCOMPARE(widget.m_touchBeginCount, 1); + QCOMPARE(widget.m_touchUpdateCount, 3); + QCOMPARE(widget.m_touchEndCount, 1); +} + void tst_QWidget::styleSheetPropagation() { QTableView tw; diff --git a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp index 9c549365ff..38b473e5ae 100644 --- a/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp +++ b/tests/auto/widgets/widgets/qdialogbuttonbox/tst_qdialogbuttonbox.cpp @@ -90,6 +90,7 @@ private slots: // void buttons(); void testDelete(); + void testSignalEmissionAfterDelete_QTBUG_45835(); void testRemove(); void testMultipleAdd(); void testStandardButtonMapping_data(); @@ -111,6 +112,7 @@ private: tst_QDialogButtonBox::tst_QDialogButtonBox() { + qRegisterMetaType(); } tst_QDialogButtonBox::~tst_QDialogButtonBox() @@ -414,6 +416,70 @@ void tst_QDialogButtonBox::testDelete() QCOMPARE(buttonBox.buttons().count(), 0); } +class ObjectDeleter : public QObject +{ + Q_OBJECT +public slots: + void deleteButton(QAbstractButton *button) + { + delete button; + } + + void deleteSender() + { + delete sender(); + } +}; + +void tst_QDialogButtonBox::testSignalEmissionAfterDelete_QTBUG_45835() +{ + { + QDialogButtonBox buttonBox; + QCOMPARE(buttonBox.buttons().count(), 0); + + QSignalSpy buttonClickedSpy(&buttonBox, &QDialogButtonBox::clicked); + QVERIFY(buttonClickedSpy.isValid()); + + QSignalSpy buttonBoxAcceptedSpy(&buttonBox, &QDialogButtonBox::accepted); + QVERIFY(buttonBoxAcceptedSpy.isValid()); + + QPushButton *button = buttonBox.addButton("Test", QDialogButtonBox::AcceptRole); + QCOMPARE(buttonBox.buttons().count(), 1); + + ObjectDeleter objectDeleter; + connect(&buttonBox, &QDialogButtonBox::clicked, &objectDeleter, &ObjectDeleter::deleteButton); + + button->click(); + + QCOMPARE(buttonBox.buttons().count(), 0); + QCOMPARE(buttonClickedSpy.count(), 1); + QCOMPARE(buttonBoxAcceptedSpy.count(), 1); + } + + { + QPointer buttonBox(new QDialogButtonBox); + QCOMPARE(buttonBox->buttons().count(), 0); + + QSignalSpy buttonClickedSpy(buttonBox.data(), &QDialogButtonBox::clicked); + QVERIFY(buttonClickedSpy.isValid()); + + QSignalSpy buttonBoxAcceptedSpy(buttonBox.data(), &QDialogButtonBox::accepted); + QVERIFY(buttonBoxAcceptedSpy.isValid()); + + QPushButton *button = buttonBox->addButton("Test", QDialogButtonBox::AcceptRole); + QCOMPARE(buttonBox->buttons().count(), 1); + + ObjectDeleter objectDeleter; + connect(buttonBox.data(), &QDialogButtonBox::clicked, &objectDeleter, &ObjectDeleter::deleteSender); + + button->click(); + + QVERIFY(buttonBox.isNull()); + QCOMPARE(buttonClickedSpy.count(), 1); + QCOMPARE(buttonBoxAcceptedSpy.count(), 0); + } +} + void tst_QDialogButtonBox::testMultipleAdd() { // Add a button into the thing multiple times. diff --git a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index ade9f72543..2bbc2e05b7 100644 --- a/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -764,6 +764,8 @@ void tst_QDockWidget::restoreDockWidget() restoreWindow.show(); QVERIFY(QTest::qWaitForWindowExposed(&restoreWindow)); QTRY_VERIFY(dock->isFloating()); + if (!QGuiApplication::platformName().compare("xcb", Qt::CaseInsensitive)) + QSKIP("Skip due to Window manager positioning issues", Abort); QTRY_COMPARE(dock->pos(), dockPos); } } diff --git a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp index 9417541040..adedc601a9 100644 --- a/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/widgets/widgets/qlineedit/tst_qlineedit.cpp @@ -304,6 +304,7 @@ private slots: void undoRedoAndEchoModes(); void clearButton(); + void clearButtonVisibleAfterSettingText_QTBUG_45518(); void sideWidgets(); void shouldShowPlaceholderText_data(); @@ -4273,6 +4274,50 @@ void tst_QLineEdit::clearButton() QVERIFY(!clearButton->isEnabled()); } +void tst_QLineEdit::clearButtonVisibleAfterSettingText_QTBUG_45518() +{ +#ifndef QT_BUILD_INTERNAL + QSKIP("This test requires a developer build"); +#else + QLineEdit edit; + edit.setMinimumWidth(200); + centerOnScreen(&edit); + QLineEditIconButton *clearButton; + clearButton = edit.findChild(); + QVERIFY(!clearButton); + + edit.setText(QStringLiteral("some text")); + edit.show(); + QVERIFY(QTest::qWaitForWindowActive(&edit)); + + QVERIFY(!edit.isClearButtonEnabled()); + + clearButton = edit.findChild(); + QVERIFY(!clearButton); + + edit.setClearButtonEnabled(true); + QVERIFY(edit.isClearButtonEnabled()); + + clearButton = edit.findChild(); + QVERIFY(clearButton); + QVERIFY(clearButton->isVisible()); + + QTRY_VERIFY(clearButton->opacity() > 0); + QTRY_COMPARE(clearButton->cursor().shape(), Qt::ArrowCursor); + + QTest::mouseClick(clearButton, Qt::LeftButton, 0, clearButton->rect().center()); + QTRY_COMPARE(edit.text(), QString()); + + QTRY_COMPARE(clearButton->opacity(), qreal(0)); + QTRY_COMPARE(clearButton->cursor().shape(), clearButton->parentWidget()->cursor().shape()); + + edit.setClearButtonEnabled(false); + QVERIFY(!edit.isClearButtonEnabled()); + clearButton = edit.findChild(); + QVERIFY(!clearButton); +#endif // QT_BUILD_INTERNAL +} + void tst_QLineEdit::sideWidgets() { QWidget testWidget; diff --git a/tests/auto/widgets/widgets/qmenu/BLACKLIST b/tests/auto/widgets/widgets/qmenu/BLACKLIST new file mode 100644 index 0000000000..de49d5ff45 --- /dev/null +++ b/tests/auto/widgets/widgets/qmenu/BLACKLIST @@ -0,0 +1,2 @@ +[task258920_mouseBorder] +osx diff --git a/tests/auto/widgets/widgets/qmenubar/BLACKLIST b/tests/auto/widgets/widgets/qmenubar/BLACKLIST index 53ea4a9148..424ab2ceed 100644 --- a/tests/auto/widgets/widgets/qmenubar/BLACKLIST +++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST @@ -2,3 +2,5 @@ ubuntu-14.04 [taskQTBUG4965_escapeEaten] ubuntu-14.04 +[task256322_highlight] +osx diff --git a/tests/manual/qscreen/README b/tests/manual/qscreen/README index 5f5da17293..cd1324276d 100644 --- a/tests/manual/qscreen/README +++ b/tests/manual/qscreen/README @@ -20,14 +20,10 @@ create two windows, and will center one each screen, by setting the geometry. Alternatively you can configure xorg.conf to create separate screens for each graphics card; then the mouse cursor can move between the screens, but -application windows cannot: each app needs to be started up on the screen that -you want to run it on. In either case, ideally this test app ought to create -two windows, one on each screen; but in fact, it can do that only if the -screens are virtual siblings. If they are on different Displays, the second -Display is not accessible to the QXcbConnection instance which was createad on -the first Display. It can be considered a known bug that the API appears to -make this possible (you would think QWindow::setScreen might work) but it -isn't possible. +application windows cannot: each app needs to be started on the screen that +you want to run it on (by specifying e.g. DISPLAY=:0.1 for the second screen), +or the application has to set the desired screen via QWindow::setScreen() before +showing the window. The physical size of the screen is considered to be a constant. This can create discrepancies in DPI when orientation is changed, or when the screen is diff --git a/tests/manual/qscreen/main.cpp b/tests/manual/qscreen/main.cpp index ef9c2efe19..8ed9cebfb4 100644 --- a/tests/manual/qscreen/main.cpp +++ b/tests/manual/qscreen/main.cpp @@ -44,6 +44,7 @@ #include #include #include +#include class ScreenPropertyWatcher : public PropertyWatcher { @@ -156,19 +157,17 @@ void screenAdded(QScreen* screen) (screen->virtualSiblings().isEmpty() ? "none" : qPrintable(screen->virtualSiblings().first()->name()))); ScreenWatcherMainWindow *w = new ScreenWatcherMainWindow(screen); - // This doesn't work. If the multiple screens are part of - // a virtual desktop (i.e. they are virtual siblings), then - // setScreen has no effect, and we need the code below to - // change the window geometry. If on the other hand the - // screens are really separate, so that windows are not - // portable between them, XCreateWindow needs to have not just - // a different root Window but also a different Display, in order to - // put the window on the other screen. That would require a - // different QXcbConnection. So this setScreen call doesn't seem useful. - //w->windowHandle()->setScreen(screen); + // Set the screen via QDesktopWidget. This corresponds to setScreen() for the underlying + // QWindow. This is essential when having separate X screens since the the positioning below is + // not sufficient to get the windows show up on the desired screen. + QList screens = QGuiApplication::screens(); + int screenNumber = screens.indexOf(screen); + Q_ASSERT(screenNumber >= 0); + w->setParent(qApp->desktop()->screen(screenNumber)); - // But this works as long as the screens are all virtual siblings w->show(); + + // Position the windows so that they end up at the center of the corresponding screen. QRect geom = w->geometry(); geom.setSize(w->sizeHint()); if (geom.height() > screen->geometry().height()) diff --git a/tools/configure/Makefile.mingw b/tools/configure/Makefile.mingw index a626bd6052..539664e7d6 100644 --- a/tools/configure/Makefile.mingw +++ b/tools/configure/Makefile.mingw @@ -4,7 +4,7 @@ CONFSRC = $(TOOLSRC)/configure RAW_PCH = configure_pch.h PCH = $(RAW_PCH).gch/c++ -DEFINES = -DUNICODE -DQT_NO_DATASTREAM -DQT_NO_CODECS -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_LITE_COMPONENT -DQT_NO_COMPRESS -DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -D_CRT_SECURE_NO_DEPRECATE -DQT_BOOTSTRAPPED -DQT_BUILD_CONFIGURE -DCOMMERCIAL_VERSION +DEFINES = -DUNICODE -DQT_NO_DATASTREAM -DQT_NO_CODECS -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_LITE_COMPONENT -DQT_NO_COMPRESS -DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -D_CRT_SECURE_NO_DEPRECATE -DQT_BOOTSTRAPPED -DQT_BUILD_CONFIGURE INCPATH = -I"../../include" -I"../../include/QtCore" -I"../../include/QtCore/$(QTVERSION)" -I"../../include/QtCore/$(QTVERSION)/QtCore" -I"$(TOOLSRC)/shared" -I"$(QTSRC)mkspecs/win32-g++" CXXFLAGS_BARE = -fno-rtti -fno-exceptions -mthreads -Wall -Wextra $(DEFINES) $(INCPATH) CXXFLAGS = -include $(RAW_PCH) $(CXXFLAGS_BARE) diff --git a/tools/configure/Makefile.win32 b/tools/configure/Makefile.win32 index 148872525a..da5b430bb1 100644 --- a/tools/configure/Makefile.win32 +++ b/tools/configure/Makefile.win32 @@ -3,7 +3,7 @@ TOOLSRC = $(QTSRC)tools CONFSRC = $(TOOLSRC)\configure PCH = configure_pch.pch -DEFINES = -DUNICODE -DQT_NO_CODECS -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_LITE_COMPONENT -DQT_NO_COMPRESS -DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -D_CRT_SECURE_NO_DEPRECATE -DQT_BOOTSTRAPPED -DQT_BUILD_CONFIGURE -DCOMMERCIAL_VERSION +DEFINES = -DUNICODE -DQT_NO_CODECS -DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_LITE_COMPONENT -DQT_NO_COMPRESS -DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -D_CRT_SECURE_NO_DEPRECATE -DQT_BOOTSTRAPPED -DQT_BUILD_CONFIGURE INCPATH = -I"..\..\include" -I"..\..\include\QtCore" -I"..\..\include\QtCore\$(QTVERSION)" -I"..\..\include\QtCore\$(QTVERSION)\QtCore" -I"$(TOOLSRC)\shared" -I"$(QTSRC)mkspecs\win32-msvc2008" CXXFLAGS_BARE = -nologo -Zc:wchar_t -W3 -GR -EHsc -w34100 -w34189 $(CFLAGS_CRT) $(EXTRA_CXXFLAGS) $(DEFINES) $(INCPATH) CXXFLAGS = -FIconfigure_pch.h -Yuconfigure_pch.h -Fp$(PCH) -MP $(CXXFLAGS_BARE) diff --git a/tools/configure/configure.pro b/tools/configure/configure.pro index 13ab3746ed..939c9ea5ab 100644 --- a/tools/configure/configure.pro +++ b/tools/configure/configure.pro @@ -134,5 +134,3 @@ SOURCES = main.cpp configureapp.cpp environment.cpp tools.cpp \ $$QT_SOURCE_TREE/src/corelib/plugin/quuid.cpp \ $$QT_SOURCE_TREE/src/corelib/tools/qcryptographichash.cpp \ $$QT_SOURCE_TREE/tools/shared/windows/registry.cpp - -DEFINES += COMMERCIAL_VERSION diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index c0e98507c7..3bf0546ac1 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -34,9 +34,7 @@ #include "configureapp.h" #include "environment.h" -#ifdef COMMERCIAL_VERSION -# include "tools.h" -#endif +#include "tools.h" #include #include @@ -244,6 +242,8 @@ Configure::Configure(int& argc, char** argv) dictionary[ "USE_GOLD_LINKER" ] = "no"; + dictionary[ "ENABLE_NEW_DTAGS" ] = "no"; + dictionary[ "SHARED" ] = "yes"; dictionary[ "STATIC_RUNTIME" ] = "no"; @@ -471,6 +471,10 @@ void Configure::parseCmdLine() dictionary[ "USE_GOLD_LINKER" ] = "yes"; else if (configCmdLine.at(i) == "-no-use-gold-linker") dictionary[ "USE_GOLD_LINKER" ] = "no"; + else if (configCmdLine.at(i) == "-enable-new-dtags") + dictionary[ "ENABLE_NEW_DTAGS" ] = "yes"; + else if (configCmdLine.at(i) == "-disable-new-dtags") + dictionary[ "ENABLE_NEW_DTAGS" ] = "no"; else if (configCmdLine.at(i) == "-shared") dictionary[ "SHARED" ] = "yes"; else if (configCmdLine.at(i) == "-static") @@ -1793,6 +1797,9 @@ bool Configure::displayHelp() desc("USE_GOLD_LINKER", "yes", "-use-gold-linker", "Link using the GNU gold linker (gcc only)."); desc("USE_GOLD_LINKER", "no", "-no-use-gold-linker", "Do not link using the GNU gold linker.\n"); + desc("ENABLE_NEW_DTAGS", "yes", "-enable-new-dtags", "Use new DTAGS for RPATH (Linux only)."); + desc("ENABLE_NEW_DTAGS", "no", "-disable-new-dtags", "Do not use new DTAGS for RPATH.\n"); + desc("SHARED", "yes", "-shared", "Create and use shared Qt libraries."); desc("SHARED", "no", "-static", "Create and use static Qt libraries.\n"); @@ -2675,6 +2682,9 @@ void Configure::generateOutputVars() if (dictionary[ "USE_GOLD_LINKER" ] == "yes") qmakeConfig += "use_gold_linker"; + if (dictionary[ "ENABLE_NEW_DTAGS" ] == "yes") + qmakeConfig += "enable_new_dtags"; + if (dictionary[ "SHARED" ] == "no") qtConfig += "static"; else @@ -3030,16 +3040,6 @@ void Configure::generateOutputVars() if (!qmakeStylePlugins.isEmpty()) qmakeVars += QString("style-plugins += ") + qmakeStylePlugins.join(' '); - if (dictionary["QMAKESPEC"].endsWith("-g++")) { - QString includepath = qgetenv("INCLUDE"); - const bool hasSh = !QStandardPaths::findExecutable(QStringLiteral("sh.exe")).isEmpty(); - QChar separator = (!includepath.contains(":\\") && hasSh ? QChar(':') : QChar(';')); - qmakeVars += QString("TMPPATH = $$quote($$(INCLUDE))"); - qmakeVars += QString("QMAKE_INCDIR_POST += $$split(TMPPATH,\"%1\")").arg(separator); - qmakeVars += QString("TMPPATH = $$quote($$(LIB))"); - qmakeVars += QString("QMAKE_LIBDIR_POST += $$split(TMPPATH,\"%1\")").arg(separator); - } - if (!dictionary[ "QMAKESPEC" ].length()) { cout << "Configure could not detect your compiler. QMAKESPEC must either" << endl << "be defined as an environment variable, or specified as an" << endl @@ -3458,6 +3458,14 @@ void Configure::generateQConfigPri() << "QT_MINOR_VERSION = " << dictionary["VERSION_MINOR"] << endl << "QT_PATCH_VERSION = " << dictionary["VERSION_PATCH"] << endl; + configStream << endl + << "QT_EDITION = " << dictionary["EDITION"] << endl; + + if (dictionary["EDITION"] != "OpenSource" && dictionary["EDITION"] != "Preview") { + configStream << "QT_LICHECK = " << dictionary["LICHECK"] << endl; + configStream << "QT_RELEASE_DATE = " << dictionary["RELEASEDATE"] << endl; + } + if (!dictionary["CFG_SYSROOT"].isEmpty() && dictionary["CFG_GCC_SYSROOT"] == "yes") { configStream << endl << "# sysroot" << endl @@ -4379,8 +4387,10 @@ bool Configure::showLicense(QString orgLicenseFile) bool showLgpl2 = true; QString licenseFile = orgLicenseFile; QString theLicense; - if (dictionary["EDITION"] == "OpenSource" || dictionary["EDITION"] == "Snapshot") { - if (platform() != ANDROID || dictionary["ANDROID_STYLE_ASSETS"] == "no") { + if (dictionary["EDITION"] == "OpenSource") { + if (platform() != WINDOWS_RT + && platform() != WINDOWS_CE + && (platform() != ANDROID || dictionary["ANDROID_STYLE_ASSETS"] == "no")) { theLicense = "GNU Lesser General Public License (LGPL) version 2.1" "\nor the GNU Lesser General Public License (LGPL) version 3"; } else { @@ -4402,7 +4412,7 @@ bool Configure::showLicense(QString orgLicenseFile) cout << "You are licensed to use this software under the terms of" << endl << "the " << theLicense << "." << endl << endl; - if (dictionary["EDITION"] == "OpenSource" || dictionary["EDITION"] == "Snapshot") { + if (dictionary["EDITION"] == "OpenSource") { cout << "Type '3' to view the Lesser GNU General Public License version 3 (LGPLv3)." << endl; if (showLgpl2) cout << "Type 'L' to view the Lesser GNU General Public License version 2.1 (LGPLv2.1)." << endl; @@ -4421,7 +4431,7 @@ bool Configure::showLicense(QString orgLicenseFile) } else if (accept == 'n') { return false; } else { - if (dictionary["EDITION"] == "OpenSource" || dictionary["EDITION"] == "Snapshot") { + if (dictionary["EDITION"] == "OpenSource") { if (accept == '3') licenseFile = orgLicenseFile + "/LICENSE.LGPLv3"; else @@ -4497,19 +4507,9 @@ void Configure::readLicense() cout << endl << "Cannot find the GPL license files! Please download the Open Source version of the library." << endl; dictionary["DONE"] = "error"; } -#ifdef COMMERCIAL_VERSION else { Tools::checkLicense(dictionary, sourcePath, buildPath); } -#else // !COMMERCIAL_VERSION - else { - cout << endl << "Error: This is the Open Source version of Qt." - << endl << "If you want to use Enterprise features of Qt," - << endl << "information use the contact form at http://www.qt.io/contact-us" - << endl << "to purchase a license." << endl << endl; - dictionary["DONE"] = "error"; - } -#endif } void Configure::reloadCmdLine() diff --git a/tools/configure/environment.cpp b/tools/configure/environment.cpp index 63c1e8a1f0..11064a757d 100644 --- a/tools/configure/environment.cpp +++ b/tools/configure/environment.cpp @@ -611,9 +611,9 @@ QStringList Environment::headerPaths(Compiler compiler) foreach (const QFileInfo &version, mingwLibDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) headerPaths += version.absoluteFilePath() + QLatin1String("/include"); } + } else { + headerPaths = splitPathList(QString::fromLocal8Bit(getenv("INCLUDE"))); } - // MinGW: Although gcc doesn't care about INCLUDE, qmake automatically adds it via -I - headerPaths += splitPathList(QString::fromLocal8Bit(getenv("INCLUDE"))); // Add Direct X SDK for ANGLE const QString directXSdk = detectDirectXSdk(); @@ -627,9 +627,9 @@ QStringList Environment::libraryPaths(Compiler compiler) QStringList libraryPaths; if (compiler == CC_MINGW) { libraryPaths = mingwPaths(detectMinGW(), "lib"); + } else { + libraryPaths = splitPathList(QString::fromLocal8Bit(qgetenv("LIB"))); } - // MinGW: Although gcc doesn't care about LIB, qmake automatically adds it via -L - libraryPaths += splitPathList(QString::fromLocal8Bit(qgetenv("LIB"))); // Add Direct X SDK for ANGLE const QString directXSdk = detectDirectXSdk(); diff --git a/tools/configure/tools.cpp b/tools/configure/tools.cpp index 83d969ce16..095e798332 100644 --- a/tools/configure/tools.cpp +++ b/tools/configure/tools.cpp @@ -54,6 +54,8 @@ void Tools::checkLicense(QMap &dictionary, return; } + dictionary["LICHECK"] = "licheck.exe"; + const QString licenseChecker = QDir::toNativeSeparators(sourcePath + "/bin/licheck.exe");