Merge remote-tracking branch 'origin/5.13' into dev

Conflicts:
	src/gui/util/qshaderformat.cpp
	src/gui/util/qshaderformat_p.h
	src/widgets/graphicsview/qgraphicsitem_p.h

Change-Id: Idafd88eb9a0a15b4af29f6143d009c1ec8ceecca
This commit is contained in:
Liang Qi 2019-04-24 09:52:30 +02:00
commit dc37318684
87 changed files with 1258 additions and 448 deletions

View File

@ -1111,7 +1111,7 @@ foreach my $lib (@modules_to_sync) {
elsif (!$shadow) { elsif (!$shadow) {
$pri_install_pfiles.= "$pri_install_iheader ";; $pri_install_pfiles.= "$pri_install_iheader ";;
} }
$pri_injections .= fixPaths($iheader, $out_basedir) $pri_injections .= fixPaths($iheader, $build_basedir)
.":".($no_stamp ? "^" : "").fixPaths($oheader, "$out_basedir/include/$lib") .":".($no_stamp ? "^" : "").fixPaths($oheader, "$out_basedir/include/$lib")
.$injection." " if ($shadow); .$injection." " if ($shadow);
} }

View File

@ -139,8 +139,8 @@ Build options:
-coverage {trace-pc-guard} -coverage {trace-pc-guard}
Add code coverage instrumentation (Clang only) Add code coverage instrumentation (Clang only)
-c++std <edition> .... Select C++ standard <edition> [c++1z/c++14/c++11] -c++std <edition> .... Select C++ standard <edition> [c++2a/c++17/c++14/c++11]
(Not supported with MSVC) (Not supported with MSVC 2015)
-sse2 ................ Use SSE2 instructions [auto] -sse2 ................ Use SSE2 instructions [auto]
-sse3/-ssse3/-sse4.1/-sse4.2/-avx/-avx2/-avx512 -sse3/-ssse3/-sse4.1/-sse4.2/-avx/-avx2/-avx512

View File

@ -319,7 +319,7 @@
} }
}, },
"c++1z": { "c++1z": {
"label": "C++1z support", "label": "C++17 support",
"type": "compile", "type": "compile",
"test": { "test": {
"head": [ "head": [
@ -339,6 +339,20 @@
"qmake": "CONFIG += c++11 c++14 c++1z" "qmake": "CONFIG += c++11 c++14 c++1z"
} }
}, },
"c++2a": {
"label": "C++2a support",
"type": "compile",
"test": {
"head": [
"#if __cplusplus > 201703L",
"// Compiler claims to support experimental C++2a, trust it",
"#else",
"# error __cplusplus must be > 201703L (the value for C++17)",
"#endif"
],
"qmake": "CONFIG += c++11 c++14 c++1z c++2a"
}
},
"precompile_header": { "precompile_header": {
"label": "precompiled header support", "label": "precompiled header support",
"type": "compile", "type": "compile",
@ -907,10 +921,16 @@
"output": [ "publicFeature", "publicQtConfig" ] "output": [ "publicFeature", "publicQtConfig" ]
}, },
"c++1z": { "c++1z": {
"label": "C++1z", "label": "C++17",
"condition": "features.c++14 && tests.c++1z", "condition": "features.c++14 && tests.c++1z",
"output": [ "publicFeature", "publicQtConfig" ] "output": [ "publicFeature", "publicQtConfig" ]
}, },
"c++2a": {
"label": "C++2a",
"autoDetect": false,
"condition": "features.c++1z && tests.c++2a",
"output": [ "publicFeature", "publicQtConfig" ]
},
"c89": { "c89": {
"label": "C89" "label": "C89"
}, },
@ -1413,7 +1433,7 @@ Configure with '-qreal float' to create a build that is binary-compatible with 5
{ {
"message": "Using C++ standard", "message": "Using C++ standard",
"type": "firstAvailableFeature", "type": "firstAvailableFeature",
"args": "c++1z c++14 c++11" "args": "c++2a c++1z c++14 c++11"
}, },
{ {
"type": "feature", "type": "feature",

View File

@ -14,21 +14,26 @@ defineTest(qtConfCommandline_qmakeArgs) {
} }
defineTest(qtConfCommandline_cxxstd) { defineTest(qtConfCommandline_cxxstd) {
msvc: \
qtConfAddError("Command line option -c++std is not supported with MSVC compilers.")
arg = $${1} arg = $${1}
val = $${2} val = $${2}
isEmpty(val): val = $$qtConfGetNextCommandlineArg() isEmpty(val): val = $$qtConfGetNextCommandlineArg()
!contains(val, "^-.*"):!isEmpty(val) { !contains(val, "^-.*"):!isEmpty(val) {
contains(val, "(c\+\+)?11") { contains(val, "(c\+\+)?11") {
qtConfCommandlineSetInput("c++14", "no") qtConfCommandlineSetInput("c++14", "no")
qtConfCommandlineSetInput("c++1z", "no")
qtConfCommandlineSetInput("c++2a", "no")
} else: contains(val, "(c\+\+)?(14|1y)") { } else: contains(val, "(c\+\+)?(14|1y)") {
qtConfCommandlineSetInput("c++14", "yes") qtConfCommandlineSetInput("c++14", "yes")
qtConfCommandlineSetInput("c++1z", "no") qtConfCommandlineSetInput("c++1z", "no")
} else: contains(val, "(c\+\+)?(1z)") { qtConfCommandlineSetInput("c++2a", "no")
} else: contains(val, "(c\+\+)?(17|1z)") {
qtConfCommandlineSetInput("c++14", "yes") qtConfCommandlineSetInput("c++14", "yes")
qtConfCommandlineSetInput("c++1z", "yes") qtConfCommandlineSetInput("c++1z", "yes")
qtConfCommandlineSetInput("c++2a", "no")
} else: contains(val, "(c\+\+)?(2a)") {
qtConfCommandlineSetInput("c++14", "yes")
qtConfCommandlineSetInput("c++1z", "yes")
qtConfCommandlineSetInput("c++2a", "yes")
} else { } else {
qtConfAddError("Invalid argument $$val to command line parameter $$arg") qtConfAddError("Invalid argument $$val to command line parameter $$arg")
} }

82
dist/changes-5.12.3 vendored Normal file
View File

@ -0,0 +1,82 @@
Qt 5.12.3 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.12.0 through 5.12.2.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
https://doc.qt.io/qt-5/index.html
The Qt version 5.12 series is binary compatible with the 5.11.x series.
Applications compiled for 5.11 will continue to run with 5.12.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
https://bugreports.qt.io/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
****************************************************************************
* Third-Party Code *
****************************************************************************
- Changed classification of the wintab license from Public Domain to
Custom.
****************************************************************************
* QtCore *
****************************************************************************
- Event system:
* [QTBUG-72438] Fixed a possible race condition on Windows that would
cause an interrupted event loop to be stuck until more events were
posted.
- Logging system:
* [QTBUG-74359] Fixed the compilation of qCDebug("", ...) when debug
output was disabled.
- QCollator:
* [QTBUG-74209] Fixed a bug that caused QCompare to incorrect return a
sorting order on Windows if the Win32 API failed.
- QDateTime / QTimeZone:
* [QTBUG-74614] Fixed handling of timezones that contain no DST
transitions.
- QProcess:
* [QTBUG-73778] Fixed a crash when calling closeWriteChannel() on Windows.
****************************************************************************
* QtSql *
****************************************************************************
- When cross-compiling pg_config, mysql_config are not looked up in PATH
anymore. Pass -psql_config path/to/pg_config or -mysql_config
path/to/mysql_config to explicitly enable PSQL or MySQL in this setup.
****************************************************************************
* Platform Specific Changes *
****************************************************************************
- Android:
* Text fields with ImhNoPredictiveText set are no longer working around
keyboards that disregard this setting. To enforce the workaround, the
environment variable
QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT should be set.
* [QTBUG-74029] Added entries in the AndroidManifest.xml for specific
portrait and landscape splash screens. If one is present for the current
orientation, it will be preferred over the generic one.
- Linux:
* [QTBUG-74526] Changed the way we use the statx() system call to use a
fallback mechanism provided by the GNU C library. This should allow Qt
applications that are compiled with glibc >= 2.28 to run even on kernels
older than 4.11.
- Windows:
* [QTBUG-74062] Fixed QToolTip pop-ups and QComboBox animation pop-ups
being off by a few pixels on Windows 10.

View File

@ -35,9 +35,11 @@ QMAKE_CXXFLAGS_DISABLE_LTCG = $$QMAKE_CFLAGS_DISABLE_LTCG
QMAKE_CXXFLAGS_CXX11 = -std=c++11 QMAKE_CXXFLAGS_CXX11 = -std=c++11
QMAKE_CXXFLAGS_CXX14 = -std=c++1y QMAKE_CXXFLAGS_CXX14 = -std=c++1y
QMAKE_CXXFLAGS_CXX1Z = -std=c++1z QMAKE_CXXFLAGS_CXX1Z = -std=c++1z
QMAKE_CXXFLAGS_CXX2A = -std=c++2a
QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11 QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11
QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++1y QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++1y
QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z
QMAKE_CXXFLAGS_GNUCXX2A = -std=gnu++2a
QMAKE_LFLAGS_CXX11 = QMAKE_LFLAGS_CXX11 =
QMAKE_LFLAGS_CXX14 = QMAKE_LFLAGS_CXX14 =

View File

@ -32,9 +32,11 @@ QMAKE_CFLAGS_GNUC11 = -std=gnu11
QMAKE_CXXFLAGS_CXX11 = -std=c++11 QMAKE_CXXFLAGS_CXX11 = -std=c++11
QMAKE_CXXFLAGS_CXX14 = -std=c++1y QMAKE_CXXFLAGS_CXX14 = -std=c++1y
QMAKE_CXXFLAGS_CXX1Z = -std=c++1z QMAKE_CXXFLAGS_CXX1Z = -std=c++1z
QMAKE_CXXFLAGS_CXX2A = -std=c++2a
QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11 QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11
QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++1y QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++1y
QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z
QMAKE_CXXFLAGS_GNUCXX2A = -std=gnu++2a
QMAKE_LFLAGS_CXX11 = QMAKE_LFLAGS_CXX11 =
QMAKE_LFLAGS_CXX14 = QMAKE_LFLAGS_CXX14 =
QMAKE_LFLAGS_CXX1Z = QMAKE_LFLAGS_CXX1Z =

View File

@ -116,6 +116,8 @@ greaterThan(QMAKE_MSC_VER, 1910) {
greaterThan(QMAKE_MSC_VER, 1919) { greaterThan(QMAKE_MSC_VER, 1919) {
# Visual Studio 2019 (16.0) / Visual C++ 19.20 and up # Visual Studio 2019 (16.0) / Visual C++ 19.20 and up
MSVC_VER = 16.0 MSVC_VER = 16.0
QMAKE_CXXFLAGS_CXX2A = -std:c++latest
} }
!isEmpty(COMPAT_MKSPEC):!$$COMPAT_MKSPEC: CONFIG += $$COMPAT_MKSPEC !isEmpty(COMPAT_MKSPEC):!$$COMPAT_MKSPEC: CONFIG += $$COMPAT_MKSPEC

View File

@ -26,20 +26,29 @@ contains(CMAKE_INSTALL_LIBS_DIR, ^(/usr)?/lib(64)?.*): CMAKE_USR_MOVE_WORKAROUND
CMAKE_OUT_DIR = $$MODULE_BASE_OUTDIR/lib/cmake CMAKE_OUT_DIR = $$MODULE_BASE_OUTDIR/lib/cmake
# Core, Network, an external module named Foo
CMAKE_MODULE_NAME = $$cmakeModuleName($${MODULE}) CMAKE_MODULE_NAME = $$cmakeModuleName($${MODULE})
# QtCore, QtNetwork, still Foo
CMAKE_INCLUDE_NAME = $$eval(QT.$${MODULE}.name)
# TARGET here is the one changed at the end of qt_module.prf,
# which already contains the Qt5 prefix and QT_LIBINFIX suffix :
# Qt5Core_suffix, Qt5Network_suffix, Foo_suffix
# (or QtCore_suffix, Foo_suffix on macos with -framework)
CMAKE_QT_STEM = $${TARGET}
!generated_privates { !generated_privates {
isEmpty(SYNCQT.INJECTED_PRIVATE_HEADER_FILES):isEmpty(SYNCQT.PRIVATE_HEADER_FILES): \ isEmpty(SYNCQT.INJECTED_PRIVATE_HEADER_FILES):isEmpty(SYNCQT.PRIVATE_HEADER_FILES): \
CMAKE_NO_PRIVATE_INCLUDES = true CMAKE_NO_PRIVATE_INCLUDES = true
} }
split_incpath { split_incpath {
CMAKE_ADD_SOURCE_INCLUDE_DIRS = true CMAKE_ADD_SOURCE_INCLUDE_DIRS = true
CMAKE_SOURCE_INCLUDES = \ CMAKE_SOURCE_INCLUDES = \
$$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}) $$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME})
CMAKE_SOURCE_PRIVATE_INCLUDES = \ CMAKE_SOURCE_PRIVATE_INCLUDES = \
$$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}/$$eval(QT.$${MODULE}.VERSION) \ $$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME}/$$eval(QT.$${MODULE}.VERSION) \
$$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}/$$eval(QT.$${MODULE}.VERSION)/Qt$${CMAKE_MODULE_NAME}) $$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME}/$$eval(QT.$${MODULE}.VERSION)/$${CMAKE_INCLUDE_NAME})
cmake_extra_source_includes.input = $$PWD/data/cmake/ExtraSourceIncludes.cmake.in cmake_extra_source_includes.input = $$PWD/data/cmake/ExtraSourceIncludes.cmake.in
cmake_extra_source_includes.output = $$CMAKE_OUT_DIR/Qt5$${CMAKE_MODULE_NAME}/ExtraSourceIncludes.cmake cmake_extra_source_includes.output = $$CMAKE_OUT_DIR/Qt5$${CMAKE_MODULE_NAME}/ExtraSourceIncludes.cmake
@ -200,10 +209,6 @@ CMAKE_QT5_MODULE_DEPS = $$join(lib_deps, ";")
CMAKE_INTERFACE_MODULE_DEPS = $$join(aux_mod_deps, ";") CMAKE_INTERFACE_MODULE_DEPS = $$join(aux_mod_deps, ";")
CMAKE_INTERFACE_QT5_MODULE_DEPS = $$join(aux_lib_deps, ";") CMAKE_INTERFACE_QT5_MODULE_DEPS = $$join(aux_lib_deps, ";")
# TARGET here is the one changed at the end of qt_module.prf,
# which already contains the Qt5 prefix and QT_LIBINFIX suffix
CMAKE_QT_STEM = $${TARGET}
mac { mac {
!isEmpty(CMAKE_STATIC_TYPE) { !isEmpty(CMAKE_STATIC_TYPE) {
CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.a CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.a
@ -213,8 +218,8 @@ mac {
CMAKE_PRL_FILE_LOCATION_RELEASE = lib$${CMAKE_QT_STEM}.prl CMAKE_PRL_FILE_LOCATION_RELEASE = lib$${CMAKE_QT_STEM}.prl
} else { } else {
qt_framework { qt_framework {
CMAKE_LIB_FILE_LOCATION_DEBUG = Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}.framework/Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX} CMAKE_LIB_FILE_LOCATION_DEBUG = $${CMAKE_QT_STEM}.framework/$${CMAKE_QT_STEM}
CMAKE_LIB_FILE_LOCATION_RELEASE = Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}.framework/Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX} CMAKE_LIB_FILE_LOCATION_RELEASE = $${CMAKE_QT_STEM}.framework/$${CMAKE_QT_STEM}
CMAKE_BUILD_IS_FRAMEWORK = "true" CMAKE_BUILD_IS_FRAMEWORK = "true"
} else { } else {
CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.$$eval(QT.$${MODULE}.VERSION).dylib CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.$$eval(QT.$${MODULE}.VERSION).dylib

View File

@ -157,13 +157,13 @@ if (NOT TARGET Qt5::$${CMAKE_MODULE_NAME})
!!IF !no_module_headers !!IF !no_module_headers
!!IF !isEmpty(CMAKE_BUILD_IS_FRAMEWORK) !!IF !isEmpty(CMAKE_BUILD_IS_FRAMEWORK)
set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework\" \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework\"
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Headers\" \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Headers\"
) )
!!IF isEmpty(CMAKE_NO_PRIVATE_INCLUDES) !!IF isEmpty(CMAKE_NO_PRIVATE_INCLUDES)
set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/\" \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/\"
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/$${MODULE_INCNAME}\" \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/$${MODULE_INCNAME}\"
) )
!!ELSE !!ELSE
set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"\") set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"\")
@ -180,7 +180,7 @@ if (NOT TARGET Qt5::$${CMAKE_MODULE_NAME})
set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"\") set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"\")
!!ENDIF !!ENDIF
!!ELSE !!ELSE
set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS \"$$CMAKE_INCLUDE_DIR\" \"$${CMAKE_INCLUDE_DIR}Qt$${CMAKE_MODULE_NAME}\") set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS \"$$CMAKE_INCLUDE_DIR\" \"$${CMAKE_INCLUDE_DIR}$${CMAKE_INCLUDE_NAME}\")
!!IF isEmpty(CMAKE_NO_PRIVATE_INCLUDES) !!IF isEmpty(CMAKE_NO_PRIVATE_INCLUDES)
set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS
\"$${CMAKE_INCLUDE_DIR}$${MODULE_INCNAME}/$$VERSION\" \"$${CMAKE_INCLUDE_DIR}$${MODULE_INCNAME}/$$VERSION\"

View File

@ -121,15 +121,16 @@ breakpad {
c++17: CONFIG += c++1z c++17: CONFIG += c++1z
!c++11:!c++14:!c++1z { !c++11:!c++14:!c++1z:!c++2a {
# Qt requires C++11 since 5.7, check if we need to force a compiler option # Qt requires C++11 since 5.7, check if we need to force a compiler option
QT_COMPILER_STDCXX_no_L = $$replace(QT_COMPILER_STDCXX, "L$", "") QT_COMPILER_STDCXX_no_L = $$replace(QT_COMPILER_STDCXX, "L$", "")
!greaterThan(QT_COMPILER_STDCXX_no_L, 199711): CONFIG += c++11 !greaterThan(QT_COMPILER_STDCXX_no_L, 199711): CONFIG += c++11
} }
c++11|c++14|c++1z { c++11|c++14|c++1z|c++2a {
# Disable special compiler flags for host builds # Disable special compiler flags for host builds
!host_build|!cross_compile { !host_build|!cross_compile {
c++1z: cxxstd = CXX1Z c++2a: cxxstd = CXX2A
else: c++1z: cxxstd = CXX1Z
else: c++14: cxxstd = CXX14 else: c++14: cxxstd = CXX14
else: cxxstd = CXX11 else: cxxstd = CXX11
} else { } else {

View File

@ -145,12 +145,14 @@ import_plugins:qtConfig(static) {
# the plugin path. Unknown plugins must rely on the default link path. # the plugin path. Unknown plugins must rely on the default link path.
plug_type = $$eval(QT_PLUGIN.$${plug}.TYPE) plug_type = $$eval(QT_PLUGIN.$${plug}.TYPE)
!isEmpty(plug_type) { !isEmpty(plug_type) {
plug_name = $$QMAKE_PREFIX_STATICLIB$${plug}$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB
plug_path = $$eval(QT_PLUGIN.$${plug}.PATH) plug_path = $$eval(QT_PLUGIN.$${plug}.PATH)
isEmpty(plug_path): \ isEmpty(plug_path): \
plug_path = $$[QT_INSTALL_PLUGINS/get] plug_path = $$[QT_INSTALL_PLUGINS/get]
LIBS += -L$$plug_path/$$plug_type LIBS += $$plug_path/$$plug_type/$$plug_name
} else {
LIBS += -l$${plug}$$qtPlatformTargetSuffix()
} }
LIBS += -l$${plug}$$qtPlatformTargetSuffix()
} }
} }
@ -195,8 +197,6 @@ for(ever) {
qtProcessModuleFlags(DEFINES, QT.$${QTLIB}.DEFINES) qtProcessModuleFlags(DEFINES, QT.$${QTLIB}.DEFINES)
MODULE_INCLUDES -= $$QMAKE_DEFAULT_INCDIRS MODULE_INCLUDES -= $$QMAKE_DEFAULT_INCDIRS
MODULE_LIBS_ADD = $$MODULE_LIBS
MODULE_LIBS_ADD -= $$QMAKE_DEFAULT_LIBDIRS
# Frameworks shouldn't need include paths, but much code does not use # Frameworks shouldn't need include paths, but much code does not use
# module-qualified #includes, so by default we add paths which point # module-qualified #includes, so by default we add paths which point
@ -209,23 +209,17 @@ for(ever) {
!isEmpty(MODULE_MODULE) { !isEmpty(MODULE_MODULE) {
contains(MODULE_CONFIG, lib_bundle) { contains(MODULE_CONFIG, lib_bundle) {
framework = $$MODULE_MODULE framework = $$MODULE_MODULE
# Linking frameworks by absolute path does not work.
LIBS$$var_sfx += -framework $$framework LIBS$$var_sfx += -framework $$framework
} else { } else {
!isEmpty(MODULE_LIBS_ADD): \
LIBS$$var_sfx += -L$$MODULE_LIBS_ADD
lib = $$MODULE_MODULE$$qtPlatformTargetSuffix() lib = $$MODULE_MODULE$$qtPlatformTargetSuffix()
LIBS$$var_sfx += -l$$lib win32|contains(MODULE_CONFIG, staticlib) {
lib = $$MODULE_LIBS/$$QMAKE_PREFIX_STATICLIB$${lib}.$$QMAKE_EXTENSION_STATICLIB
contains(MODULE_CONFIG, staticlib): \ PRE_TARGETDEPS += $$lib
PRE_TARGETDEPS *= $$MODULE_LIBS/$${QMAKE_PREFIX_STATICLIB}$${lib}.$${QMAKE_EXTENSION_STATICLIB} } else {
lib = $$MODULE_LIBS/$$QMAKE_PREFIX_SHLIB$${lib}.$$QMAKE_EXTENSION_SHLIB
!isEmpty(QMAKE_LSB) {
!isEmpty(MODULE_LIBS_ADD): \
QMAKE_LFLAGS *= --lsb-libpath=$$MODULE_LIBS_ADD
QMAKE_LFLAGS *= --lsb-shared-libs=$$lib
QMAKE_LIBDIR *= /opt/lsb/lib
} }
LIBS$$var_sfx += $$lib
} }
} }
QMAKE_USE$$var_sfx += $$MODULE_USES QMAKE_USE$$var_sfx += $$MODULE_USES
@ -295,7 +289,8 @@ contains(all_qt_module_deps, qml): \
for (key, IMPORTS._KEYS_) { for (key, IMPORTS._KEYS_) {
PATH = $$eval(IMPORTS.$${key}.path) PATH = $$eval(IMPORTS.$${key}.path)
PLUGIN = $$eval(IMPORTS.$${key}.plugin) PLUGIN = $$eval(IMPORTS.$${key}.plugin)
!isEmpty(PATH):!isEmpty(PLUGIN): LIBS *= -L$$PATH -l$${PLUGIN}$$qtPlatformTargetSuffix() !isEmpty(PATH):!isEmpty(PLUGIN): \
LIBS += $$PATH/$$QMAKE_PREFIX_STATICLIB$${PLUGIN}$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB
} }
# create qml_plugin_import.cpp # create qml_plugin_import.cpp

View File

@ -17,6 +17,7 @@ DEFINES *= QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
qtConfig(c++11): CONFIG += c++11 strict_c++ qtConfig(c++11): CONFIG += c++11 strict_c++
qtConfig(c++14): CONFIG += c++14 qtConfig(c++14): CONFIG += c++14
qtConfig(c++1z): CONFIG += c++1z qtConfig(c++1z): CONFIG += c++1z
qtConfig(c++2a): CONFIG += c++2a
qtConfig(c99): CONFIG += c99 qtConfig(c99): CONFIG += c99
qtConfig(c11): CONFIG += c11 qtConfig(c11): CONFIG += c11
qtConfig(stack-protector-strong): CONFIG += stack_protector_strong qtConfig(stack-protector-strong): CONFIG += stack_protector_strong

View File

@ -526,6 +526,17 @@ defineTest(qtConfSetupLibraries) {
} }
} }
defineReplace(qtGccSysrootifiedPath) {
return($$replace(1, ^=, $$[QT_SYSROOT]))
}
defineReplace(qtGccSysrootifiedPaths) {
sysrootified =
for (path, 1): \
sysrootified += $$qtGccSysrootifiedPath($$path)
return($$sysrootified)
}
# libs-var, libs, in-paths, out-paths-var # libs-var, libs, in-paths, out-paths-var
defineTest(qtConfResolveLibs) { defineTest(qtConfResolveLibs) {
ret = true ret = true
@ -542,6 +553,7 @@ defineTest(qtConfResolveLibs) {
out += $$l out += $$l
} else: contains(l, "^-L.*") { } else: contains(l, "^-L.*") {
lp = $$replace(l, "^-L", ) lp = $$replace(l, "^-L", )
gcc: lp = $$qtGccSysrootifiedPath($$lp)
!exists($$lp/.) { !exists($$lp/.) {
qtLog("Library path $$val_escape(lp) is invalid.") qtLog("Library path $$val_escape(lp) is invalid.")
ret = false ret = false
@ -615,6 +627,7 @@ defineTest(qtConfResolveAllLibs) {
# libs-var, in-paths, libs # libs-var, in-paths, libs
defineTest(qtConfResolvePathLibs) { defineTest(qtConfResolvePathLibs) {
ret = true ret = true
gcc: 2 = $$qtGccSysrootifiedPaths($$2)
for (libdir, 2) { for (libdir, 2) {
!exists($$libdir/.) { !exists($$libdir/.) {
qtLog("Library path $$val_escape(libdir) is invalid.") qtLog("Library path $$val_escape(libdir) is invalid.")
@ -665,6 +678,7 @@ defineReplace(qtConfGetTestIncludes) {
# includes-var, in-paths, test-object-var # includes-var, in-paths, test-object-var
defineTest(qtConfResolvePathIncs) { defineTest(qtConfResolvePathIncs) {
ret = true ret = true
gcc: 2 = $$qtGccSysrootifiedPaths($$2)
for (incdir, 2) { for (incdir, 2) {
!exists($$incdir/.) { !exists($$incdir/.) {
qtLog("Include path $$val_escape(incdir) is invalid.") qtLog("Include path $$val_escape(incdir) is invalid.")

View File

@ -23,7 +23,7 @@ load(qt_build_paths)
QMAKE_SYNCQT += -module $$mod QMAKE_SYNCQT += -module $$mod
QMAKE_SYNCQT += \ QMAKE_SYNCQT += \
-version $$VERSION -outdir $$system_quote($$MODULE_BASE_OUTDIR) \ -version $$VERSION -outdir $$system_quote($$MODULE_BASE_OUTDIR) \
-builddir $$system_quote($$shadowed($$MODULE_BASE_INDIR)) $$MODULE_SYNCQT_DIR -builddir $$system_quote($$REAL_MODULE_BASE_OUTDIR) $$MODULE_SYNCQT_DIR
!silent: message($$QMAKE_SYNCQT) !silent: message($$QMAKE_SYNCQT)
system($$QMAKE_SYNCQT)|error("Failed to run: $$QMAKE_SYNCQT") system($$QMAKE_SYNCQT)|error("Failed to run: $$QMAKE_SYNCQT")

View File

@ -1,13 +1,21 @@
QT_FOR_CONFIG += gui QT_FOR_CONFIG += gui
defineTest(prependOpenGlLib) {
path = $$QT.core.libs/$$QMAKE_PREFIX_STATICLIB$$1
ext = .$$QMAKE_EXTENSION_STATICLIB
QMAKE_LIBS_OPENGL_ES2 = $${path}$${ext} $$QMAKE_LIBS_OPENGL_ES2
QMAKE_LIBS_OPENGL_ES2_DEBUG = $${path}d$${ext} $$QMAKE_LIBS_OPENGL_ES2_DEBUG
export(QMAKE_LIBS_OPENGL_ES2)
export(QMAKE_LIBS_OPENGL_ES2_DEBUG)
}
qtConfig(opengles2) { qtConfig(opengles2) {
# Depending on the configuration we use libQtANGLE or libEGL and libGLESv2 # Depending on the configuration we use libQtANGLE or libEGL and libGLESv2
qtConfig(combined-angle-lib) { qtConfig(combined-angle-lib) {
QMAKE_LIBS_OPENGL_ES2 = -l$${LIBQTANGLE_NAME} $$QMAKE_LIBS_OPENGL_ES2 prependOpenGlLib($$LIBQTANGLE_NAME)
QMAKE_LIBS_OPENGL_ES2_DEBUG = -l$${LIBQTANGLE_NAME}d $$QMAKE_LIBS_OPENGL_ES2_DEBUG
} else { } else {
QMAKE_LIBS_OPENGL_ES2 = -l$${LIBEGL_NAME} -l$${LIBGLESV2_NAME} $$QMAKE_LIBS_OPENGL_ES2 prependOpenGlLib($$LIBGLESV2_NAME)
QMAKE_LIBS_OPENGL_ES2_DEBUG = -l$${LIBEGL_NAME}d -l$${LIBGLESV2_NAME}d $$QMAKE_LIBS_OPENGL_ES2_DEBUG prependOpenGlLib($$LIBEGL_NAME)
} }
# For Desktop, use the ANGLE library location passed on from configure. # For Desktop, use the ANGLE library location passed on from configure.
INCLUDEPATH += $$QMAKE_INCDIR_OPENGL_ES2 INCLUDEPATH += $$QMAKE_INCDIR_OPENGL_ES2

View File

@ -6,10 +6,9 @@ contains(TEMPLATE, ".*app") {
qt:for(entryLib, $$list($$unique(QMAKE_LIBS_QT_ENTRY))) { qt:for(entryLib, $$list($$unique(QMAKE_LIBS_QT_ENTRY))) {
isEqual(entryLib, -lqtmain) { isEqual(entryLib, -lqtmain) {
!contains(QMAKE_DEFAULT_LIBDIRS, $$QT.core.libs): \ lib = $$QT.core.libs/$${QMAKE_PREFIX_STATICLIB}qtmain$$QT_LIBINFIX$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB
QMAKE_LIBS += -L$$QT.core.libs PRE_TARGETDEPS += $$lib
CONFIG(debug, debug|release): QMAKE_LIBS += $${entryLib}$${QT_LIBINFIX}d QMAKE_LIBS += $$lib
else: QMAKE_LIBS += $${entryLib}$${QT_LIBINFIX}
} else { } else {
QMAKE_LIBS += $${entryLib} QMAKE_LIBS += $${entryLib}
} }

View File

@ -13,7 +13,6 @@ load(qt_config)
QMAKE_LIBS_THREAD += -lrt QMAKE_LIBS_THREAD += -lrt
QMAKE_LSB = 1
QMAKE_CC = lsbcc QMAKE_CC = lsbcc
QMAKE_CXX = lsbc++ QMAKE_CXX = lsbc++

View File

@ -1271,6 +1271,41 @@
\snippet code/doc_src_qmake-manual.pro 36 \snippet code/doc_src_qmake-manual.pro 36
\c INSTALLS has a \c{.CONFIG} member that can take several values:
\table
\header
\li Value
\li Description
\row
\li no_check_exists
\li If not set, qmake looks to see if the files to install actually
exist. If these files don't exist, qmake doesnt create the
install rule. Use this config value if you need to install
files that are generated as part of your build process, like
HTML files created by qdoc.
\row
\li nostrip
\li If set, the typical Unix strip functionality is turned off and
the debug information will remain in the binary.
\row
\li executable
\li On Unix, this sets the executable flag.
\row
\li no_build
\li When you do a \c{make install}, and you don't have a build of
the project yet, the project is first built, and then installed.
If you don't want this behavior, set this config value to ensure
that the build target is not added as a dependency to the install
target.
\row
\li no_default_install
\li A project has a top-level project target where, when you do a
\c{make install}, everything is installed. But, if you have an
install target with this config value set, it's not installed by
default. You then have to explicitly say \c{make install_<file>}.
\endtable
For more information, see \l{Installing Files}. For more information, see \l{Installing Files}.
This variable is also used to specify which additional files will be This variable is also used to specify which additional files will be
@ -1580,6 +1615,14 @@
The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf}
and rarely needs to be modified. and rarely needs to be modified.
\target QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
\section1 QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
Specifies the C compiler flags for release builds where
\c{force_debug_info} is set in \c{CONFIG}.
The value of this variable is typically handled by
qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified.
\target QMAKE_CFLAGS_SHLIB \target QMAKE_CFLAGS_SHLIB
\section1 QMAKE_CFLAGS_SHLIB \section1 QMAKE_CFLAGS_SHLIB
@ -1648,6 +1691,14 @@
The value of this variable is typically handled by The value of this variable is typically handled by
qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified.
\target QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO
\section1 QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO
Specifies the C++ compiler flags for release builds where
\c{force_debug_info} is set in \c{CONFIG}.
The value of this variable is typically handled by
qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified.
\target QMAKE_CXXFLAGS_SHLIB \target QMAKE_CXXFLAGS_SHLIB
\section1 QMAKE_CXXFLAGS_SHLIB \section1 QMAKE_CXXFLAGS_SHLIB
@ -2028,6 +2079,12 @@
The value of this variable is typically handled by The value of this variable is typically handled by
qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified.
\section1 QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
Specifies the linker flags for release builds where \c{force_debug_info} is
set in \c{CONFIG}. The value of this variable is typically handled by
qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified.
\section1 QMAKE_LFLAGS_APP \section1 QMAKE_LFLAGS_APP
Specifies the linker flags for building applications. Specifies the linker flags for building applications.
@ -4813,6 +4870,7 @@
\li Unix \li Unix
\list \list
\li GCC 3.4 and above \li GCC 3.4 and above
\li clang
\endlist \endlist
\endlist \endlist

View File

@ -143,6 +143,7 @@ const char _InterfaceIdentifierFileName[] = "InterfaceIdentifierFileName";
const char _IntermediateDirectory[] = "IntermediateDirectory"; const char _IntermediateDirectory[] = "IntermediateDirectory";
const char _KeyContainer[] = "KeyContainer"; const char _KeyContainer[] = "KeyContainer";
const char _KeyFile[] = "KeyFile"; const char _KeyFile[] = "KeyFile";
const char _LanguageStandard[] = "LanguageStandard";
const char _LargeAddressAware[] = "LargeAddressAware"; const char _LargeAddressAware[] = "LargeAddressAware";
const char _LinkDLL[] = "LinkDLL"; const char _LinkDLL[] = "LinkDLL";
const char _LinkErrorReporting[] = "LinkErrorReporting"; const char _LinkErrorReporting[] = "LinkErrorReporting";
@ -1478,6 +1479,7 @@ void VCXProjectWriter::write(XmlOutput &xml, const VCCLCompilerTool &tool)
<< attrTagT(_IntrinsicFunctions, tool.EnableIntrinsicFunctions) << attrTagT(_IntrinsicFunctions, tool.EnableIntrinsicFunctions)
<< attrTagT(_MinimalRebuild, tool.MinimalRebuild) << attrTagT(_MinimalRebuild, tool.MinimalRebuild)
<< attrTagT(_MultiProcessorCompilation, tool.MultiProcessorCompilation) << attrTagT(_MultiProcessorCompilation, tool.MultiProcessorCompilation)
<< attrTagS(_LanguageStandard, tool.LanguageStandard)
<< attrTagS(_ObjectFileName, tool.ObjectFile) << attrTagS(_ObjectFileName, tool.ObjectFile)
<< attrTagT(_OmitDefaultLibName, tool.OmitDefaultLibName) << attrTagT(_OmitDefaultLibName, tool.OmitDefaultLibName)
<< attrTagT(_OmitFramePointers, tool.OmitFramePointers) << attrTagT(_OmitFramePointers, tool.OmitFramePointers)

View File

@ -1147,6 +1147,14 @@ bool VCCLCompilerTool::parseOption(const char* option)
ShowIncludes = _True; ShowIncludes = _True;
break; break;
} }
if (strlen(option) > 8 && second == 't' && third == 'd') {
const QString version = option + 8;
static const QStringList knownVersions = { "14", "17", "latest" };
if (knownVersions.contains(version)) {
LanguageStandard = "stdcpp" + version;
break;
}
}
found = false; break; found = false; break;
case 'u': case 'u':
if (!second) if (!second)

View File

@ -526,6 +526,7 @@ public:
triState ImproveFloatingPointConsistency; triState ImproveFloatingPointConsistency;
inlineExpansionOption InlineFunctionExpansion; inlineExpansionOption InlineFunctionExpansion;
triState KeepComments; triState KeepComments;
QString LanguageStandard;
triState MinimalRebuild; triState MinimalRebuild;
QString ObjectFile; QString ObjectFile;
triState OmitDefaultLibName; triState OmitDefaultLibName;

View File

@ -364,6 +364,23 @@ Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attri
return display; return display;
} }
//static
void Display::CleanupDisplays()
{
// ~Display takes care of removing the entry from the according map
{
ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
while (!displays->empty())
delete displays->begin()->second;
}
{
DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
while (!displays->empty())
delete displays->begin()->second;
}
}
Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice) Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
: mImplementation(nullptr), : mImplementation(nullptr),
mDisplayId(displayId), mDisplayId(displayId),

View File

@ -65,6 +65,7 @@ class Display final : angle::NonCopyable
static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap); static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap);
static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,
const AttributeMap &attribMap); const AttributeMap &attribMap);
static void CleanupDisplays();
static const ClientExtensions &GetClientExtensions(); static const ClientExtensions &GetClientExtensions();
static const std::string &GetClientExtensionString(); static const std::string &GetClientExtensionString();

View File

@ -13,6 +13,7 @@
#include "common/tls.h" #include "common/tls.h"
#include "libANGLE/Thread.h" #include "libANGLE/Thread.h"
#include "libANGLE/Display.h"
namespace gl namespace gl
{ {
@ -140,6 +141,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID)
return static_cast<BOOL>(egl::DeallocateCurrentThread()); return static_cast<BOOL>(egl::DeallocateCurrentThread());
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
egl::Display::CleanupDisplays();
return static_cast<BOOL>(egl::TerminateProcess()); return static_cast<BOOL>(egl::TerminateProcess());
} }

View File

@ -0,0 +1,78 @@
From d8ca4f6d0d8fffd8319f340685e03751049678ae Mon Sep 17 00:00:00 2001
From: Oliver Wolff <oliver.wolff@qt.io>
Date: Tue, 16 Apr 2019 10:19:27 +0200
Subject: [PATCH] ANGLE: clean up displays on dll unload
If the displays are not cleaned up on dll unloading, profilers might
report memory leaks.
Change-Id: I04cbc3c2448bfb450f7d840e216827f86856e963
---
src/3rdparty/angle/src/libANGLE/Display.cpp | 17 +++++++++++++++++
src/3rdparty/angle/src/libANGLE/Display.h | 1 +
.../angle/src/libGLESv2/global_state.cpp | 2 ++
3 files changed, 20 insertions(+)
diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp
index 735b472787..0bb0bb05b1 100644
--- a/src/3rdparty/angle/src/libANGLE/Display.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Display.cpp
@@ -364,6 +364,23 @@ Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attri
return display;
}
+//static
+void Display::CleanupDisplays()
+{
+ // ~Display takes care of removing the entry from the according map
+ {
+ ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap();
+ while (!displays->empty())
+ delete displays->begin()->second;
+ }
+
+ {
+ DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap();
+ while (!displays->empty())
+ delete displays->begin()->second;
+ }
+}
+
Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice)
: mImplementation(nullptr),
mDisplayId(displayId),
diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h
index aa1d1c3b37..2a1c386d75 100644
--- a/src/3rdparty/angle/src/libANGLE/Display.h
+++ b/src/3rdparty/angle/src/libANGLE/Display.h
@@ -65,6 +65,7 @@ class Display final : angle::NonCopyable
static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap);
static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay,
const AttributeMap &attribMap);
+ static void CleanupDisplays();
static const ClientExtensions &GetClientExtensions();
static const std::string &GetClientExtensionString();
diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.cpp b/src/3rdparty/angle/src/libGLESv2/global_state.cpp
index c5f3dfe4e1..26045bf5b2 100644
--- a/src/3rdparty/angle/src/libGLESv2/global_state.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/global_state.cpp
@@ -13,6 +13,7 @@
#include "common/tls.h"
#include "libANGLE/Thread.h"
+#include "libANGLE/Display.h"
namespace gl
{
@@ -140,6 +141,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID)
return static_cast<BOOL>(egl::DeallocateCurrentThread());
case DLL_PROCESS_DETACH:
+ egl::Display::CleanupDisplays();
return static_cast<BOOL>(egl::TerminateProcess());
}
--
2.20.1.windows.1

View File

@ -61,6 +61,9 @@
#endif #endif
#if defined(__cplusplus) #if defined(__cplusplus)
#ifdef Q_CC_MINGW
# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
#endif
#include <time.h> #include <time.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE

View File

@ -310,9 +310,18 @@ static QString readSymLink(const QFileSystemEntry &link)
const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset]; const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset];
result = QString::fromWCharArray(PathBuffer, length); result = QString::fromWCharArray(PathBuffer, length);
} }
// cut-off "//?/" and "/??/" // cut-off "\\?\" and "\??\"
if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\')) if (result.size() > 4
&& result.at(0) == QLatin1Char('\\')
&& result.at(2) == QLatin1Char('?')
&& result.at(3) == QLatin1Char('\\')) {
result = result.mid(4); result = result.mid(4);
// cut off UNC in addition when the link points at a UNC share
// in which case we need to prepend another backslash to get \\server\share
if (result.leftRef(3) == QLatin1String("UNC")) {
result.replace(0, 3, QLatin1Char('\\'));
}
}
} }
free(rdb); free(rdb);
CloseHandle(handle); CloseHandle(handle);

View File

@ -3619,7 +3619,7 @@ QModelIndex QAbstractTableModel::sibling(int row, int column, const QModelIndex
bool QAbstractTableModel::hasChildren(const QModelIndex &parent) const bool QAbstractTableModel::hasChildren(const QModelIndex &parent) const
{ {
if (parent.model() == this || !parent.isValid()) if (!parent.isValid())
return rowCount(parent) > 0 && columnCount(parent) > 0; return rowCount(parent) > 0 && columnCount(parent) > 0;
return false; return false;
} }

View File

@ -515,7 +515,7 @@ struct Q_CORE_EXPORT QMetaObject
Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr) Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr)
{ {
return invokeMethodImpl(context, return invokeMethodImpl(context,
new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(function), new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
type, type,
ret); ret);
} }
@ -527,7 +527,7 @@ struct Q_CORE_EXPORT QMetaObject
invokeMethod(QObject *context, Func function, typename std::result_of<Func()>::type *ret) invokeMethod(QObject *context, Func function, typename std::result_of<Func()>::type *ret)
{ {
return invokeMethodImpl(context, return invokeMethodImpl(context,
new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(function), new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
Qt::AutoConnection, Qt::AutoConnection,
ret); ret);
} }

View File

@ -58,6 +58,9 @@
#endif #endif
#include <cmath> #include <cmath>
#ifdef Q_CC_MINGW
# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
#endif
#include <time.h> #include <time.h>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
# include <qt_windows.h> # include <qt_windows.h>

View File

@ -335,7 +335,7 @@ public:
inline bool operator>(const QDateTime &other) const { return other < *this; } inline bool operator>(const QDateTime &other) const { return other < *this; }
inline bool operator>=(const QDateTime &other) const { return !(*this < other); } inline bool operator>=(const QDateTime &other) const { return !(*this < other); }
#if QT_DEPRECATED_SINCE(5, 2) #if QT_DEPRECATED_SINCE(5, 2) // ### Qt 6: remove
QT_DEPRECATED void setUtcOffset(int seconds); QT_DEPRECATED void setUtcOffset(int seconds);
QT_DEPRECATED int utcOffset() const; QT_DEPRECATED int utcOffset() const;
#endif // QT_DEPRECATED_SINCE #endif // QT_DEPRECATED_SINCE

View File

@ -2482,6 +2482,17 @@ QString QLocale::toString(double i, char f, int prec) const
Returns a QLocale object initialized to the "C" locale. Returns a QLocale object initialized to the "C" locale.
This locale is based on en_US but with various quirks of its own, such as
simplified number formatting and its own date formatting. It implements the
POSIX standards that describe the behavior of standard library functions of
the "C" programming language.
Among other things, this means its collation order is based on the ASCII
values of letters, so that (for case-sensitive sorting) all upper-case
letters sort before any lower-case one (rather than each letter's upper- and
lower-case forms sorting adjacent to one another, before the next letter's
two forms).
\sa system() \sa system()
*/ */

View File

@ -104,7 +104,7 @@
This enumerated type is used to specify a language. This enumerated type is used to specify a language.
\value AnyLanguage \value AnyLanguage
\value C The "C" locale is identical in behavior to English/UnitedStates. \value C A simplified English locale; see QLocale::c()
\value Abkhazian \value Abkhazian
\value Afan Obsolete, please use Oromo \value Afan Obsolete, please use Oromo

View File

@ -46,6 +46,8 @@
#include "qwindow.h" #include "qwindow.h"
#include "qplatformwindow.h" #include "qplatformwindow.h"
#include <private/qwindow_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
/*! /*!
@ -199,12 +201,18 @@ void QOffscreenSurface::create()
if (QThread::currentThread() != qGuiApp->thread()) if (QThread::currentThread() != qGuiApp->thread())
qWarning("Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures."); qWarning("Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures.");
d->offscreenWindow = new QWindow(d->screen); d->offscreenWindow = new QWindow(d->screen);
// Make the window frameless to prevent Windows from enlarging it, should it
// violate the minimum title bar width on the platform.
d->offscreenWindow->setFlags(d->offscreenWindow->flags()
| Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
d->offscreenWindow->setObjectName(QLatin1String("QOffscreenSurface")); d->offscreenWindow->setObjectName(QLatin1String("QOffscreenSurface"));
// Remove this window from the global list since we do not want it to be destroyed when closing the app. // Remove this window from the global list since we do not want it to be destroyed when closing the app.
// The QOffscreenSurface has to be usable even after exiting the event loop. // The QOffscreenSurface has to be usable even after exiting the event loop.
QGuiApplicationPrivate::window_list.removeOne(d->offscreenWindow); QGuiApplicationPrivate::window_list.removeOne(d->offscreenWindow);
d->offscreenWindow->setSurfaceType(QWindow::OpenGLSurface); d->offscreenWindow->setSurfaceType(QWindow::OpenGLSurface);
d->offscreenWindow->setFormat(d->requestedFormat); d->offscreenWindow->setFormat(d->requestedFormat);
// Prevent QPlatformWindow::initialGeometry() and platforms from setting a default geometry.
qt_window_private(d->offscreenWindow)->setAutomaticPositionAndResizeEnabled(false);
d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height()); d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height());
d->offscreenWindow->create(); d->offscreenWindow->create();
} }

View File

@ -366,40 +366,35 @@ void qt_mac_scale_region(QRegion *region, qreal scaleFactor)
// ---------------------- QMacCGContext ---------------------- // ---------------------- QMacCGContext ----------------------
QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) : context(0) QMacCGContext::QMacCGContext(QPaintDevice *paintDevice)
{ {
// In Qt 5, QWidget and QPixmap (and QImage) paint devices are all QImages under the hood. initialize(paintDevice);
QImage *image = 0;
if (paintDevice->devType() == QInternal::Image) {
image = static_cast<QImage *>(paintDevice);
} else if (paintDevice->devType() == QInternal::Pixmap) {
const QPixmap *pm = static_cast<const QPixmap*>(paintDevice);
QPlatformPixmap *data = const_cast<QPixmap *>(pm)->data_ptr().data();
if (data && data->classId() == QPlatformPixmap::RasterClass) {
image = data->buffer();
} else {
qDebug("QMacCGContext: Unsupported pixmap class");
}
} else if (paintDevice->devType() == QInternal::Widget) {
// TODO test: image = static_cast<QImage *>(static_cast<const QWidget *>(paintDevice)->backingStore()->paintDevice());
qDebug("QMacCGContext: not implemented: Widget class");
}
if (!image)
return; // Context type not supported.
QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
context = CGBitmapContextCreate(image->bits(), image->width(), image->height(), 8,
image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image));
CGContextTranslateCTM(context, 0, image->height());
const qreal devicePixelRatio = paintDevice->devicePixelRatioF();
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
CGContextScaleCTM(context, 1, -1);
} }
QMacCGContext::QMacCGContext(QPainter *painter) : context(0) void QMacCGContext::initialize(QPaintDevice *paintDevice)
{
// Find the underlying QImage of the paint device
switch (int deviceType = paintDevice->devType()) {
case QInternal::Pixmap: {
auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle();
if (platformPixmap && platformPixmap->classId() == QPlatformPixmap::RasterClass)
initialize(platformPixmap->buffer());
else
qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId();
break;
}
case QInternal::Image:
initialize(static_cast<const QImage *>(paintDevice));
break;
case QInternal::Widget:
qWarning() << "QMacCGContext: not implemented: Widget class";
break;
default:
qWarning() << "QMacCGContext:: Unsupported paint device type" << deviceType;
}
}
QMacCGContext::QMacCGContext(QPainter *painter)
{ {
QPaintEngine *paintEngine = painter->paintEngine(); QPaintEngine *paintEngine = painter->paintEngine();
@ -414,51 +409,68 @@ QMacCGContext::QMacCGContext(QPainter *painter) : context(0)
return; return;
} }
int devType = painter->device()->devType(); if (paintEngine->type() != QPaintEngine::Raster) {
if (paintEngine->type() == QPaintEngine::Raster qWarning() << "QMacCGContext:: Unsupported paint engine type" << paintEngine->type();
&& (devType == QInternal::Widget || return;
devType == QInternal::Pixmap ||
devType == QInternal::Image)) {
const QImage *image = static_cast<const QImage *>(paintEngine->paintDevice());
QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8,
image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image));
// Invert y axis
CGContextTranslateCTM(context, 0, image->height());
CGContextScaleCTM(context, 1, -1);
const qreal devicePixelRatio = image->devicePixelRatio();
if (devType == QInternal::Widget) {
// Set the clip rect which is an intersection of the system clip
// and the painter clip. To make matters more interesting these
// are in device pixels and device-independent pixels, respectively.
QRegion clip = painter->paintEngine()->systemClip(); // get system clip in device pixels
QTransform native = painter->deviceTransform(); // get device transform. dx/dy is in device pixels
if (painter->hasClipping()) {
QRegion r = painter->clipRegion(); // get painter clip, which is in device-independent pixels
qt_mac_scale_region(&r, devicePixelRatio); // scale painter clip to device pixels
r.translate(native.dx(), native.dy());
if (clip.isEmpty())
clip = r;
else
clip &= r;
}
qt_mac_clip_cg(context, clip, 0); // clip in device pixels
// Scale the context so that painting happens in device-independent pixels
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
CGContextTranslateCTM(context, native.dx() / devicePixelRatio, native.dy() / devicePixelRatio);
} else {
// Scale to paint in device-independent pixels
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
}
} else {
qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType;
} }
// The raster paint engine always operates on a QImage
Q_ASSERT(paintEngine->paintDevice()->devType() == QInternal::Image);
// On behalf of one of these supported painter devices
switch (int painterDeviceType = painter->device()->devType()) {
case QInternal::Pixmap:
case QInternal::Image:
case QInternal::Widget:
break;
default:
qWarning() << "QMacCGContext:: Unsupported paint device type" << painterDeviceType;
return;
}
// Applying the clip is so entangled with the rest of the context setup
// that for simplicity we just pass in the painter.
initialize(static_cast<const QImage *>(paintEngine->paintDevice()), painter);
}
void QMacCGContext::initialize(const QImage *image, QPainter *painter)
{
QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8,
image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image));
// Invert y axis
CGContextTranslateCTM(context, 0, image->height());
CGContextScaleCTM(context, 1, -1);
const qreal devicePixelRatio = image->devicePixelRatio();
if (painter && painter->device()->devType() == QInternal::Widget) {
// Set the clip rect which is an intersection of the system clip and the painter clip
QRegion clip = painter->paintEngine()->systemClip();
QTransform deviceTransform = painter->deviceTransform();
if (painter->hasClipping()) {
// To make matters more interesting the painter clip is in device-independent pixels,
// so we need to scale it to match the device-pixels of the system clip.
QRegion painterClip = painter->clipRegion();
qt_mac_scale_region(&painterClip, devicePixelRatio);
painterClip.translate(deviceTransform.dx(), deviceTransform.dy());
if (clip.isEmpty())
clip = painterClip;
else
clip &= painterClip;
}
qt_mac_clip_cg(context, clip, 0);
CGContextTranslateCTM(context, deviceTransform.dx(), deviceTransform.dy());
}
// Scale the context so that painting happens in device-independent pixels
CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -51,6 +51,8 @@
// We mean it. // We mean it.
// //
#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/private/qtguiglobal_p.h> #include <QtGui/private/qtguiglobal_p.h>
#include <QtGui/qregion.h> #include <QtGui/qregion.h>
#include <QtGui/qpalette.h> #include <QtGui/qpalette.h>
@ -89,38 +91,16 @@ Q_GUI_EXPORT QBrush qt_mac_toQBrush(CGColorRef color);
class Q_GUI_EXPORT QMacCGContext class Q_GUI_EXPORT QMacCGContext
{ {
public: public:
inline QMacCGContext() { context = 0; } QMacCGContext() = default;
QMacCGContext(QPaintDevice *pdev); QMacCGContext(QPaintDevice *pdev);
QMacCGContext(QPainter *p); QMacCGContext(QPainter *p);
inline QMacCGContext(CGContextRef cg, bool takeOwnership = false) {
context = cg; operator CGContextRef() { return context; }
if (!takeOwnership)
CGContextRetain(context);
}
inline QMacCGContext(const QMacCGContext &copy) : context(0) { *this = copy; }
inline ~QMacCGContext() {
if (context)
CGContextRelease(context);
}
inline bool isNull() const { return context; }
inline operator CGContextRef() { return context; }
inline QMacCGContext &operator=(const QMacCGContext &copy) {
if (context)
CGContextRelease(context);
context = copy.context;
CGContextRetain(context);
return *this;
}
inline QMacCGContext &operator=(CGContextRef cg) {
if (context)
CGContextRelease(context);
context = cg;
CGContextRetain(context); //we do not take ownership
return *this;
}
private: private:
CGContextRef context; void initialize(QPaintDevice *paintDevice);
void initialize(const QImage *, QPainter *painter = nullptr);
QCFType<CGContextRef> context;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
QShaderFormat::QShaderFormat() noexcept QShaderFormat::QShaderFormat() noexcept
: m_api(NoApi) : m_api(NoApi)
, m_shaderType(Fragment)
{ {
} }
@ -106,6 +107,9 @@ bool QShaderFormat::supports(const QShaderFormat &other) const noexcept
if (m_version < other.m_version) if (m_version < other.m_version)
return false; return false;
if (m_shaderType != other.m_shaderType)
return false;
const auto containsAllExtensionsFromOther = std::includes(m_extensions.constBegin(), const auto containsAllExtensionsFromOther = std::includes(m_extensions.constBegin(),
m_extensions.constEnd(), m_extensions.constEnd(),
other.m_extensions.constBegin(), other.m_extensions.constBegin(),
@ -119,12 +123,23 @@ bool QShaderFormat::supports(const QShaderFormat &other) const noexcept
return true; return true;
} }
QShaderFormat::ShaderType QShaderFormat::shaderType() const Q_DECL_NOTHROW
{
return m_shaderType;
}
void QShaderFormat::setShaderType(QShaderFormat::ShaderType shaderType) Q_DECL_NOTHROW
{
m_shaderType = shaderType;
}
bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept
{ {
return lhs.api() == rhs.api() return lhs.api() == rhs.api()
&& lhs.version() == rhs.version() && lhs.version() == rhs.version()
&& lhs.extensions() == rhs.extensions() && lhs.extensions() == rhs.extensions()
&& lhs.vendor() == rhs.vendor(); && lhs.vendor() == rhs.vendor()
&& lhs.shaderType() == rhs.shaderType();
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -69,6 +69,15 @@ public:
OpenGLES OpenGLES
}; };
enum ShaderType : int {
Vertex = 0,
TessellationControl,
TessellationEvaluation,
Geometry,
Fragment,
Compute
};
Q_GUI_EXPORT QShaderFormat() noexcept; Q_GUI_EXPORT QShaderFormat() noexcept;
Q_GUI_EXPORT Api api() const noexcept; Q_GUI_EXPORT Api api() const noexcept;
@ -86,11 +95,15 @@ public:
Q_GUI_EXPORT bool isValid() const noexcept; Q_GUI_EXPORT bool isValid() const noexcept;
Q_GUI_EXPORT bool supports(const QShaderFormat &other) const noexcept; Q_GUI_EXPORT bool supports(const QShaderFormat &other) const noexcept;
Q_GUI_EXPORT ShaderType shaderType() const Q_DECL_NOTHROW;
Q_GUI_EXPORT void setShaderType(ShaderType shaderType) Q_DECL_NOTHROW;
private: private:
Api m_api; Api m_api;
QVersionNumber m_version; QVersionNumber m_version;
QStringList m_extensions; QStringList m_extensions;
QString m_vendor; QString m_vendor;
ShaderType m_shaderType;
}; };
Q_GUI_EXPORT bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept; Q_GUI_EXPORT bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept;

View File

@ -40,6 +40,7 @@
#include "qshadergenerator_p.h" #include "qshadergenerator_p.h"
#include "qshaderlanguage_p.h" #include "qshaderlanguage_p.h"
#include <QRegularExpression>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -56,7 +57,10 @@ namespace
case QShaderLanguage::Const: case QShaderLanguage::Const:
return "const"; return "const";
case QShaderLanguage::Input: case QShaderLanguage::Input:
return "varying"; if (format.shaderType() == QShaderFormat::Vertex)
return "attribute";
else
return "varying";
case QShaderLanguage::Output: case QShaderLanguage::Output:
return ""; // Although fragment shaders for <=2 only have fixed outputs return ""; // Although fragment shaders for <=2 only have fixed outputs
case QShaderLanguage::Uniform: case QShaderLanguage::Uniform:
@ -314,12 +318,22 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); }); [enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
}; };
QVector<QString> globalInputVariables;
const QRegularExpression globalInputExtractRegExp(QStringLiteral("^.*\\s+(\\w+).*;$"));
const QVector<QShaderNode> nodes = graph.nodes(); const QVector<QShaderNode> nodes = graph.nodes();
for (const QShaderNode &node : nodes) { for (const QShaderNode &node : nodes) {
if (intersectsEnabledLayers(node.layers())) { if (intersectsEnabledLayers(node.layers())) {
const QByteArrayList headerSnippets = node.rule(format).headerSnippets; const QByteArrayList headerSnippets = node.rule(format).headerSnippets;
for (const QByteArray &snippet : headerSnippets) { for (const QByteArray &snippet : headerSnippets) {
code << replaceParameters(snippet, node, format); code << replaceParameters(snippet, node, format);
// If node is an input, record the variable name into the globalInputVariables vector
if (node.type() == QShaderNode::Input) {
const QRegularExpressionMatch match = globalInputExtractRegExp.match(QString::fromUtf8(code.last()));
if (match.hasMatch())
globalInputVariables.push_back(match.captured(1));
}
} }
} }
} }
@ -328,6 +342,14 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
code << QByteArrayLiteral("void main()"); code << QByteArrayLiteral("void main()");
code << QByteArrayLiteral("{"); code << QByteArrayLiteral("{");
// Table to store temporary variables that should be replaced by global
// variables. This avoids having vec3 v56 = vertexPosition; when we could
// just use vertexPosition directly.
// The added benefit is when having arrays, we don't try to create
// mat4 v38 = skinningPalelette[100] which would be invalid
QHash<QString, QString> localReferencesToGlobalInputs;
const QRegularExpression localToGlobalRegExp(QStringLiteral("^.*\\s+(\\w+)\\s*=\\s*(\\w+).*;$"));
for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) { for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) {
const QShaderNode node = statement.node; const QShaderNode node = statement.node;
QByteArray line = node.rule(format).substitution; QByteArray line = node.rule(format).substitution;
@ -338,6 +360,9 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
const bool isInput = port.direction == QShaderNodePort::Input; const bool isInput = port.direction == QShaderNodePort::Input;
const int portIndex = statement.portIndex(portDirection, portName); const int portIndex = statement.portIndex(portDirection, portName);
Q_ASSERT(portIndex >= 0);
const int variableIndex = isInput ? statement.inputs.at(portIndex) const int variableIndex = isInput ? statement.inputs.at(portIndex)
: statement.outputs.at(portIndex); : statement.outputs.at(portIndex);
if (variableIndex < 0) if (variableIndex < 0)
@ -345,15 +370,51 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8()); const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8());
const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex)); const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex));
line.replace(placeholder, variable); line.replace(placeholder, variable);
} }
code << QByteArrayLiteral(" ") + replaceParameters(line, node, format); const QByteArray substitutionedLine = replaceParameters(line, node, format);
// Record name of temporary variable that possibly references a global input
// We will replace the temporary variables by the matching global variables later
bool isAGlobalInputVariable = false;
if (node.type() == QShaderNode::Input) {
const QRegularExpressionMatch match = localToGlobalRegExp.match(QString::fromUtf8(substitutionedLine));
if (match.hasMatch()) {
const QString globalVariable = match.captured(2);
if (globalInputVariables.contains(globalVariable)) {
const QString localVariable = match.captured(1);
// TO DO: Clean globalVariable (remove brackets ...)
localReferencesToGlobalInputs.insert(localVariable, globalVariable);
isAGlobalInputVariable = true;
}
}
}
// Only insert content for lines aren't inputs or have not matching
// globalVariables for now
if (!isAGlobalInputVariable)
code << QByteArrayLiteral(" ") + substitutionedLine;
} }
code << QByteArrayLiteral("}"); code << QByteArrayLiteral("}");
code << QByteArray(); code << QByteArray();
return code.join('\n');
// Replace occurrences of local variables which reference a global variable
// by the global variables directly
auto it = localReferencesToGlobalInputs.cbegin();
const auto end = localReferencesToGlobalInputs.cend();
QString codeString = QString::fromUtf8(code.join('\n'));
while (it != end) {
const QRegularExpression r(QStringLiteral("\\b(%1)([\\b|\\.|;|\\)|\\[|\\s|\\*|\\+|\\/|\\-|,])").arg(it.key()),
QRegularExpression::MultilineOption);
codeString.replace(r, QStringLiteral("%1\\2").arg(it.value()));
++it;
}
return codeString.toUtf8();
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -251,6 +251,17 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
break; break;
} }
// We default out to a Fragment ShaderType if nothing is specified
// as that was the initial behavior we introduced
const QString shaderType = formatObject.value(QStringLiteral("shaderType")).toString();
format.setShaderType(shaderType == QStringLiteral("Fragment") ? QShaderFormat::Fragment
: shaderType == QStringLiteral("Vertex") ? QShaderFormat::Vertex
: shaderType == QStringLiteral("TessellationControl") ? QShaderFormat::TessellationControl
: shaderType == QStringLiteral("TessellationEvaluation") ? QShaderFormat::TessellationEvaluation
: shaderType == QStringLiteral("Geometry") ? QShaderFormat::Geometry
: shaderType == QStringLiteral("Compute") ? QShaderFormat::Compute
: QShaderFormat::Fragment);
const QByteArray substitution = substitutionValue.toString().toUtf8(); const QByteArray substitution = substitutionValue.toString().toUtf8();
const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets")); const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));

View File

@ -385,8 +385,8 @@ QHostAddress QNetmask::address(QAbstractSocket::NetworkLayerProtocol protocol) c
\value LocalHost The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1"). \value LocalHost The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1").
\value LocalHostIPv6 The IPv6 localhost address. Equivalent to QHostAddress("::1"). \value LocalHostIPv6 The IPv6 localhost address. Equivalent to QHostAddress("::1").
\value Broadcast The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255"). \value Broadcast The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255").
\value AnyIPv4 The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interaces. \value AnyIPv4 The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interfaces.
\value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interaces. \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interfaces.
\value Any The dual stack any-address. A socket bound with this address will listen on both IPv4 and IPv6 interfaces. \value Any The dual stack any-address. A socket bound with this address will listen on both IPv4 and IPv6 interfaces.
*/ */

View File

@ -268,7 +268,7 @@ EGLConfig QEglConfigChooser::chooseConfig()
configureAttributes.append(EGL_OPENGL_ES_BIT); configureAttributes.append(EGL_OPENGL_ES_BIT);
break; break;
} }
// fall through Q_FALLTHROUGH();
default: default:
needsES2Plus = true; needsES2Plus = true;
break; break;

View File

@ -134,7 +134,7 @@ QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatform
void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share) void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share)
{ {
m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig); m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig, format);
// m_format now has the renderableType() resolved (it cannot be Default anymore) // m_format now has the renderableType() resolved (it cannot be Default anymore)
// but does not yet contain version, profile, options. // but does not yet contain version, profile, options.
m_shareContext = share ? static_cast<QEGLPlatformContext *>(share)->m_eglContext : 0; m_shareContext = share ? static_cast<QEGLPlatformContext *>(share)->m_eglContext : 0;
@ -248,6 +248,12 @@ void QEGLPlatformContext::adopt(const QVariant &nativeHandle, QPlatformOpenGLCon
value = 0; value = 0;
eglQueryContext(m_eglDisplay, context, EGL_CONTEXT_CLIENT_TYPE, &value); eglQueryContext(m_eglDisplay, context, EGL_CONTEXT_CLIENT_TYPE, &value);
if (value == EGL_OPENGL_API || value == EGL_OPENGL_ES_API) { if (value == EGL_OPENGL_API || value == EGL_OPENGL_ES_API) {
// if EGL config supports both OpenGL and OpenGL ES render type,
// q_glFormatFromConfig() with the default "referenceFormat" parameter
// will always figure it out as OpenGL render type.
// We can override it to match user's real render type.
if (value == EGL_OPENGL_ES_API)
m_format.setRenderableType(QSurfaceFormat::OpenGLES);
m_api = value; m_api = value;
eglBindAPI(m_api); eglBindAPI(m_api);
} else { } else {

View File

@ -6,7 +6,7 @@ CONFIG += static internal_module
DEFINES += QT_NO_CAST_FROM_ASCII DEFINES += QT_NO_CAST_FROM_ASCII
QMAKE_USE_PRIVATE += xlib QMAKE_USE += xlib
HEADERS += qglxconvenience_p.h HEADERS += qglxconvenience_p.h
SOURCES += qglxconvenience.cpp SOURCES += qglxconvenience.cpp

View File

@ -96,8 +96,8 @@ void QTsLibMouseHandler::readMouseData()
int x = sample.x; int x = sample.x;
int y = sample.y; int y = sample.y;
// work around missing coordinates on mouse release // coordinates on release events can contain arbitrary values, just ignore them
if (sample.pressure == 0 && sample.x == 0 && sample.y == 0) { if (sample.pressure == 0) {
x = m_x; x = m_x;
y = m_y; y = m_y;
} }

View File

@ -59,6 +59,7 @@ enum OutputConfiguration {
OutputConfigOff, OutputConfigOff,
OutputConfigPreferred, OutputConfigPreferred,
OutputConfigCurrent, OutputConfigCurrent,
OutputConfigSkip,
OutputConfigMode, OutputConfigMode,
OutputConfigModeline OutputConfigModeline
}; };
@ -191,6 +192,8 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
configuration = OutputConfigPreferred; configuration = OutputConfigPreferred;
} else if (mode == "current") { } else if (mode == "current") {
configuration = OutputConfigCurrent; configuration = OutputConfigCurrent;
} else if (mode == "skip") {
configuration = OutputConfigSkip;
} else if (sscanf(mode.constData(), "%dx%d@%d", &configurationSize.rwidth(), &configurationSize.rheight(), } else if (sscanf(mode.constData(), "%dx%d@%d", &configurationSize.rwidth(), &configurationSize.rheight(),
&configurationRefresh) == 3) &configurationRefresh) == 3)
{ {
@ -229,6 +232,11 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
return nullptr; return nullptr;
} }
if (configuration == OutputConfigSkip) {
qCDebug(qLcKmsDebug) << "Skipping output" << connectorName;
return nullptr;
}
// Get the current mode on the current crtc // Get the current mode on the current crtc
drmModeModeInfo crtc_mode; drmModeModeInfo crtc_mode;
memset(&crtc_mode, 0, sizeof crtc_mode); memset(&crtc_mode, 0, sizeof crtc_mode);

View File

@ -188,14 +188,15 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
topLeftRect.width(), topLeftRect.height()); topLeftRect.width(), topLeftRect.height());
} }
static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &targetWindowRect, static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &sourceWindowRect,
const QRect &targetWindowRect,
QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix) QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix)
{ {
const QRect clipRect = textures->clipRect(idx); const QRect clipRect = textures->clipRect(idx);
if (clipRect.isEmpty()) if (clipRect.isEmpty())
return; return;
const QRect rectInWindow = textures->geometry(idx); const QRect rectInWindow = textures->geometry(idx).translated(sourceWindowRect.topLeft());
const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft()); const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft());
const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height()); const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height());
@ -218,7 +219,7 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size()); const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size());
float currentOpacity = 1.0f; float currentOpacity = 1.0f;
BlendStateBinder blend; BlendStateBinder blend;
const QRect sourceWindowRect = window->sourceWindow()->geometry();
for (int i = 0; i < textures->count(); ++i) { for (int i = 0; i < textures->count(); ++i) {
uint textureId = textures->textureId(i); uint textureId = textures->textureId(i);
const float opacity = window->sourceWindow()->opacity(); const float opacity = window->sourceWindow()->opacity();
@ -243,16 +244,16 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
target = m_rotationMatrix * target; target = m_rotationMatrix * target;
m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
} else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { } else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
// Texture from an FBO belonging to a QOpenGLWidget // Texture from an FBO belonging to a QOpenGLWidget or QQuickWidget
blend.set(false); blend.set(false);
clippedBlit(textures, i, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr);
} }
} }
for (int i = 0; i < textures->count(); ++i) { for (int i = 0; i < textures->count(); ++i) {
if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
blend.set(true); blend.set(true);
clippedBlit(textures, i, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr);
} }
} }

View File

@ -300,7 +300,7 @@ void QGenericEngine::doRequestUpdate()
if (interface.flags() & QNetworkInterface::IsLoopBack) if (interface.flags() & QNetworkInterface::IsLoopBack)
continue; continue;
#ifndef Q_OS_WINRT #ifndef Q_OS_WIN
// ignore WLAN interface handled in separate engine // ignore WLAN interface handled in separate engine
if (qGetInterfaceType(interface.name()) == QNetworkConfiguration::BearerWLAN) if (qGetInterfaceType(interface.name()) == QNetworkConfiguration::BearerWLAN)
continue; continue;

View File

@ -93,6 +93,7 @@ private:
QRegion dirtyRegion; // In unscaled coordinates QRegion dirtyRegion; // In unscaled coordinates
QImage *asImage(); QImage *asImage();
qreal devicePixelRatio() const { return m_devicePixelRatio; }
private: private:
qreal m_devicePixelRatio; qreal m_devicePixelRatio;

View File

@ -460,12 +460,29 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view(); NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view(); NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
// If the backingstore is just flushed, without being painted to first, then we may
// end in a situation where the backingstore is flushed to a layer with a different
// scale factor than the one it was created for in beginPaint. This is the client's
// fault in not picking up the change in scale factor of the window and re-painting
// the backingstore accordingly. To smoothing things out, we warn about this situation,
// and change the layer's contentsScale to match the scale of the back buffer, so that
// we at least cover the whole layer. This is necessary since we set the view's
// contents placement policy to NSViewLayerContentsPlacementTopLeft, which means
// AppKit will not do any scaling on our behalf.
if (m_buffers.back()->devicePixelRatio() != flushedView.layer.contentsScale) {
qCWarning(lcQpaBackingStore) << "Back buffer dpr of" << m_buffers.back()->devicePixelRatio()
<< "doesn't match" << flushedView.layer << "contents scale of" << flushedView.layer.contentsScale
<< "- updating layer to match.";
flushedView.layer.contentsScale = m_buffers.back()->devicePixelRatio();
}
id backBufferSurface = (__bridge id)m_buffers.back()->surface(); id backBufferSurface = (__bridge id)m_buffers.back()->surface();
if (flushedView.layer.contents == backBufferSurface) { if (flushedView.layer.contents == backBufferSurface) {
// We've managed to paint to the back buffer again before Core Animation had time // We've managed to paint to the back buffer again before Core Animation had time
// to flush the transaction and persist the layer changes to the window server. // to flush the transaction and persist the layer changes to the window server, or
// The layer already knows about the back buffer, and we don't need to re-apply // we've been asked to flush without painting anything. The layer already knows about
// it to pick up the surface changes, so bail out early. // the back buffer, and we don't need to re-apply it to pick up any possible surface
// changes, so bail out early.
qCInfo(lcQpaBackingStore).nospace() << "Skipping flush of " << flushedView qCInfo(lcQpaBackingStore).nospace() << "Skipping flush of " << flushedView
<< ", layer already reflects back buffer"; << ", layer already reflects back buffer";
return; return;

View File

@ -154,6 +154,7 @@
<< "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested" << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
: [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS"); : [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
[super setLayer:layer]; [super setLayer:layer];
layer.delegate = self;
} }
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy - (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy

View File

@ -199,6 +199,10 @@ QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
QEglFSWindow *w = qt_egl_device_integration()->createWindow(window); QEglFSWindow *w = qt_egl_device_integration()->createWindow(window);
w->create(); w->create();
const auto showWithoutActivating = window->property("_q_showWithoutActivating");
if (showWithoutActivating.isValid() && showWithoutActivating.toBool())
return w;
// Activate only the window for the primary screen to make input work // Activate only the window for the primary screen to make input work
if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen()) if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen())
w->requestActivateWindow(); w->requestActivateWindow();

View File

@ -167,6 +167,9 @@ void QEglFSWindow::create()
void QEglFSWindow::destroy() void QEglFSWindow::destroy()
{ {
if (!m_flags.testFlag(Created))
return; // already destroyed
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
QOpenGLCompositor::instance()->removeWindow(this); QOpenGLCompositor::instance()->removeWindow(this);
#endif #endif

View File

@ -55,6 +55,9 @@ public:
: QEglFSWindow(w), : QEglFSWindow(w),
m_integration(integration) m_integration(integration)
{ } { }
~QEglFSKmsGbmWindow() { destroy(); }
void resetSurface() override; void resetSurface() override;
void invalidateSurface() override; void invalidateSurface() override;

View File

@ -117,6 +117,8 @@ public:
, m_framePending(false) , m_framePending(false)
{ } { }
~QEglFSKmsEglDeviceWindow() { destroy(); }
void invalidateSurface() override; void invalidateSurface() override;
void resetSurface() override; void resetSurface() override;
void flip(); void flip();

View File

@ -205,6 +205,9 @@ public:
: QEglFSWindow(w) : QEglFSWindow(w)
, m_integration(integration) , m_integration(integration)
{} {}
~QEglFSKmsVsp2Window() { destroy(); }
void resetSurface() override; void resetSurface() override;
void invalidateSurface() override; void invalidateSurface() override;
const QEglFSKmsVsp2Integration *m_integration; const QEglFSKmsVsp2Integration *m_integration;

View File

@ -41,6 +41,7 @@
#include <QtCore/qurl.h> #include <QtCore/qurl.h>
#include <QtCore/qmimedata.h> #include <QtCore/qmimedata.h>
#include "qwindowsmime.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -48,8 +49,9 @@ QT_BEGIN_NAMESPACE
\class QWindowsDropDataObject \class QWindowsDropDataObject
\brief QWindowsOleDataObject subclass specialized for handling Drag&Drop. \brief QWindowsOleDataObject subclass specialized for handling Drag&Drop.
Only allows "text/uri-list" data to be exported as CF_HDROP, to allow dropped Prevents "text/uri-list" data for local files from being exported as text
files to be attached to Office applications (instead of adding an URL link). or URLs, to allow dropped files to be attached to Office applications
(instead of creating local hyperlinks).
\internal \internal
\ingroup qt-lighthouse-win \ingroup qt-lighthouse-win
@ -80,14 +82,22 @@ QWindowsDropDataObject::QueryGetData(LPFORMATETC pformatetc)
return QWindowsOleDataObject::QueryGetData(pformatetc); return QWindowsOleDataObject::QueryGetData(pformatetc);
} }
// If the data is text/uri-list for local files, tell we can only export it as CF_HDROP. // If the data is "text/uri-list" only, and all URIs are for local files,
// we prevent it from being exported as text or URLs, to make target applications
// like MS Office attach or open the files instead of creating local hyperlinks.
bool QWindowsDropDataObject::shouldIgnore(LPFORMATETC pformatetc) const bool QWindowsDropDataObject::shouldIgnore(LPFORMATETC pformatetc) const
{ {
QMimeData *dropData = mimeData(); QMimeData *dropData = mimeData();
if (dropData && dropData->hasFormat(QStringLiteral("text/uri-list")) && (pformatetc->cfFormat != CF_HDROP)) { if (dropData && dropData->formats().size() == 1 && dropData->hasUrls()) {
QList<QUrl> urls = dropData->urls(); QString formatName = QWindowsMimeConverter::clipboardFormatName(pformatetc->cfFormat);
return std::any_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); }); if (pformatetc->cfFormat == CF_UNICODETEXT
|| pformatetc->cfFormat == CF_TEXT
|| formatName == QStringLiteral("UniformResourceLocator")
|| formatName == QStringLiteral("UniformResourceLocatorW")) {
QList<QUrl> urls = dropData->urls();
return std::all_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); });
}
} }
return false; return false;

View File

@ -879,21 +879,16 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con
#if defined(WM_APPCOMMAND) #if defined(WM_APPCOMMAND)
const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam); const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam);
// QTBUG-57198, do not send mouse-synthesized commands as key events in addition // QTBUG-57198, do not send mouse-synthesized commands as key events in addition
bool skipPressRelease = false;
switch (GET_DEVICE_LPARAM(msg.lParam)) { switch (GET_DEVICE_LPARAM(msg.lParam)) {
case FAPPCOMMAND_MOUSE: case FAPPCOMMAND_MOUSE:
return false; return false;
case FAPPCOMMAND_KEY: case FAPPCOMMAND_KEY:
// QTBUG-62838, swallow WM_KEYDOWN, WM_KEYUP for commands that are // QTBUG-62838, use WM_KEYDOWN/WM_KEYUP for commands that are reflected
// reflected in VK(s) like VK_MEDIA_NEXT_TRACK. Don't do that for // in VK(s) like VK_MEDIA_NEXT_TRACK, to get correct codes and autorepeat.
// APPCOMMAND_BROWSER_HOME as that one does not trigger two events // Don't do that for APPCOMMAND_BROWSER_HOME as that one does not trigger two events.
if (cmd != APPCOMMAND_BROWSER_HOME) { if (cmd != APPCOMMAND_BROWSER_HOME)
MSG peekedMsg; skipPressRelease = true;
if (PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_NOREMOVE)
&& peekedMsg.message == WM_KEYDOWN) {
PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_REMOVE);
PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_REMOVE);
}
}
break; break;
} }
@ -908,7 +903,8 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con
return false; return false;
const int qtKey = int(CmdTbl[cmd]); const int qtKey = int(CmdTbl[cmd]);
sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0); if (!skipPressRelease)
sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
// QTBUG-43343: Make sure to return false if Qt does not handle the key, otherwise, // QTBUG-43343: Make sure to return false if Qt does not handle the key, otherwise,
// the keys are not passed to the active media player. // the keys are not passed to the active media player.
# if QT_CONFIG(shortcut) # if QT_CONFIG(shortcut)

View File

@ -1087,7 +1087,10 @@ bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMi
const QImage image = qvariant_cast<QImage>(mimeData->imageData()); const QImage image = qvariant_cast<QImage>(mimeData->imageData());
if (image.isNull()) if (image.isNull())
return false; return false;
return cf == CF_DIBV5 || (cf == CF_DIB) || cf == int(CF_PNG); // QTBUG-64322: Use PNG only for transparent images as otherwise MS PowerPoint
// cannot handle it.
return cf == CF_DIBV5 || cf == CF_DIB
|| (cf == int(CF_PNG) && image.hasAlphaChannel());
} }
bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const

View File

@ -250,6 +250,23 @@ static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState)
return result; return result;
} }
static Qt::MouseButtons queryMouseButtons()
{
Qt::MouseButtons result = Qt::NoButton;
const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
if (GetAsyncKeyState(VK_LBUTTON) < 0)
result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
if (GetAsyncKeyState(VK_RBUTTON) < 0)
result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
if (GetAsyncKeyState(VK_MBUTTON) < 0)
result |= Qt::MidButton;
if (GetAsyncKeyState(VK_XBUTTON1) < 0)
result |= Qt::XButton1;
if (GetAsyncKeyState(VK_XBUTTON2) < 0)
result |= Qt::XButton2;
return result;
}
static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos)
{ {
QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT);
@ -531,7 +548,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
return false; return false;
const quint32 pointerId = penInfo->pointerInfo.pointerId; const qint64 sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice;
const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y); const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y);
const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left) const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left)
@ -547,7 +564,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
if (QWindowsContext::verbose > 1) if (QWindowsContext::verbose > 1)
qCDebug(lcQpaEvents).noquote().nospace() << showbase qCDebug(lcQpaEvents).noquote().nospace() << showbase
<< __FUNCTION__ << " pointerId=" << pointerId << __FUNCTION__ << " sourceDevice=" << sourceDevice
<< " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos << " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos
<< " message=" << hex << msg.message << " message=" << hex << msg.message
<< " flags=" << hex << penInfo->pointerInfo.pointerFlags; << " flags=" << hex << penInfo->pointerInfo.pointerFlags;
@ -570,7 +587,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
switch (msg.message) { switch (msg.message) {
case WM_POINTERENTER: { case WM_POINTERENTER: {
QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, pointerId); QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, sourceDevice);
m_windowUnderPointer = window; m_windowUnderPointer = window;
// The local coordinates may fall outside the window. // The local coordinates may fall outside the window.
// Wait until the next update to send the enter event. // Wait until the next update to send the enter event.
@ -583,12 +600,12 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
m_windowUnderPointer = nullptr; m_windowUnderPointer = nullptr;
m_currentWindow = nullptr; m_currentWindow = nullptr;
} }
QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, pointerId); QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, sourceDevice);
break; break;
case WM_POINTERDOWN: case WM_POINTERDOWN:
case WM_POINTERUP: case WM_POINTERUP:
case WM_POINTERUPDATE: { case WM_POINTERUPDATE: {
QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(pointerId).target; // Pass to window that grabbed it. QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(sourceDevice).target; // Pass to window that grabbed it.
if (!target && m_windowUnderPointer) if (!target && m_windowUnderPointer)
target = m_windowUnderPointer; target = m_windowUnderPointer;
if (!target) if (!target)
@ -607,7 +624,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
pressure, xTilt, yTilt, tangentialPressure, rotation, z, pressure, xTilt, yTilt, tangentialPressure, rotation, z,
pointerId, keyModifiers); sourceDevice, keyModifiers);
return false; // Allow mouse messages to be generated. return false; // Allow mouse messages to be generated.
} }
} }
@ -681,7 +698,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
} }
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam);
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
if (et == QtWindows::MouseWheelEvent) if (et == QtWindows::MouseWheelEvent)
@ -709,7 +725,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
const MouseEvent mouseEvent = eventFromMsg(msg); const MouseEvent mouseEvent = eventFromMsg(msg);
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) { if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, const Qt::MouseButtons nonclientButtons = queryMouseButtons();
QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, nonclientButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source); mouseEvent.button, mouseEvent.type, keyModifiers, source);
return false; // Allow further event processing return false; // Allow further event processing
} }
@ -725,6 +742,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
return true; return true;
} }
const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam);
handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons); handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons);
handleEnterLeave(window, currentWindowUnderPointer, globalPos); handleEnterLeave(window, currentWindowUnderPointer, globalPos);

View File

@ -113,6 +113,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
case QAccessible::ValueChanged: case QAccessible::ValueChanged:
QWindowsUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event)); QWindowsUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event));
break; break;
case QAccessible::SelectionAdd:
QWindowsUiaMainProvider::notifySelectionChange(event);
break;
case QAccessible::TextAttributeChanged: case QAccessible::TextAttributeChanged:
case QAccessible::TextColumnChanged: case QAccessible::TextColumnChanged:
case QAccessible::TextInserted: case QAccessible::TextInserted:

View File

@ -146,9 +146,33 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event) void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event)
{ {
if (QAccessibleInterface *accessible = event->accessibleInterface()) { if (QAccessibleInterface *accessible = event->accessibleInterface()) {
if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) { if (accessible->role() == QAccessible::ComboBox && accessible->childCount() > 0) {
// Notifies changes in values of controls supporting the value interface. QAccessibleInterface *listacc = accessible->child(0);
if (listacc && listacc->role() == QAccessible::List) {
int count = listacc->childCount();
for (int i = 0; i < count; ++i) {
QAccessibleInterface *item = listacc->child(i);
if (item && item->text(QAccessible::Name) == event->value()) {
if (!item->state().selected) {
if (QAccessibleActionInterface *actionInterface = item->actionInterface())
actionInterface->doAction(QAccessibleActionInterface::toggleAction());
}
break;
}
}
}
}
if (event->value().type() == QVariant::String) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
// Notifies changes in string values.
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantString(event->value().toString(), &newVal);
QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
}
} else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
// Notifies changes in values of controls supporting the value interface.
VARIANT oldVal, newVal; VARIANT oldVal, newVal;
clearVariant(&oldVal); clearVariant(&oldVal);
setVariantDouble(valueInterface->currentValue().toDouble(), &newVal); setVariantDouble(valueInterface->currentValue().toDouble(), &newVal);
@ -158,6 +182,15 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
} }
} }
void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
}
}
}
// Notifies changes in text content and selection state of text controls. // Notifies changes in text content and selection state of text controls.
void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event) void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
{ {

View File

@ -68,6 +68,7 @@ public:
static void notifyFocusChange(QAccessibleEvent *event); static void notifyFocusChange(QAccessibleEvent *event);
static void notifyStateChange(QAccessibleStateChangeEvent *event); static void notifyStateChange(QAccessibleStateChangeEvent *event);
static void notifyValueChange(QAccessibleValueChangeEvent *event); static void notifyValueChange(QAccessibleValueChangeEvent *event);
static void notifySelectionChange(QAccessibleEvent *event);
static void notifyTextChange(QAccessibleEvent *event); static void notifyTextChange(QAccessibleEvent *event);
// IUnknown // IUnknown

View File

@ -270,7 +270,9 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
// ES does not support any format option // ES does not support any format option
m_format.setOptions(QSurfaceFormat::FormatOptions()); m_format.setOptions(QSurfaceFormat::FormatOptions());
} }
// Robustness must match that of the shared context.
if (share && share->format().testOption(QSurfaceFormat::ResetNotification))
m_format.setOption(QSurfaceFormat::ResetNotification);
Q_ASSERT(glVersions.count() > 0); Q_ASSERT(glVersions.count() > 0);
for (int i = 0; !m_context && i < glVersions.count(); i++) { for (int i = 0; !m_context && i < glVersions.count(); i++) {

View File

@ -1156,66 +1156,6 @@ static QStyleHelper::WidgetSizePolicy qt_aqua_guess_size(const QWidget *widg, QS
} }
#endif #endif
static NSColor *qt_convertColorForContext(CGContextRef context, NSColor *color)
{
Q_ASSERT(color);
Q_ASSERT(context);
CGColorSpaceRef targetCGColorSpace = CGBitmapContextGetColorSpace(context);
NSColorSpace *targetNSColorSpace = [[NSColorSpace alloc] initWithCGColorSpace:targetCGColorSpace];
NSColor *adjusted = [color colorUsingColorSpace:targetNSColorSpace];
[targetNSColorSpace release];
return adjusted;
}
static NSColor *qt_colorForContext(CGContextRef context, const CGFloat (&rgba)[4])
{
Q_ASSERT(context);
auto colorSpace = CGBitmapContextGetColorSpace(context);
if (!colorSpace)
return nil;
return qt_convertColorForContext(context, [NSColor colorWithSRGBRed:rgba[0] green:rgba[1] blue:rgba[2] alpha:rgba[3]]);
}
static void qt_drawDisclosureButton(CGContextRef context, NSInteger state, bool selected, CGRect rect)
{
Q_ASSERT(context);
static const CGFloat gray[] = {0.55, 0.55, 0.55, 0.97};
static const CGFloat white[] = {1.0, 1.0, 1.0, 0.9};
NSColor *fillColor = qt_colorForContext(context, selected ? white : gray);
[fillColor setFill];
if (state == NSOffState) {
static NSBezierPath *triangle = [[NSBezierPath alloc] init];
[triangle removeAllPoints];
// In off state, a disclosure button is an equilateral triangle
// ('pointing' to the right) with a bound rect that can be described
// as NSMakeRect(0, 0, 8, 9). Inside the 'rect' it's translated by
// (2, 4).
[triangle moveToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 4)];
[triangle lineToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 4 + 9)];
[triangle lineToPoint:NSMakePoint(rect.origin.x + 2 + 8, rect.origin.y + 4 + 4.5)];
[triangle closePath];
[triangle fill];
} else {
static NSBezierPath *openTriangle = [[NSBezierPath alloc] init];
[openTriangle removeAllPoints];
// In 'on' state, the button is an equilateral triangle (looking down)
// with the bounding rect NSMakeRect(0, 0, 9, 8). Inside the 'rect'
// it's translated by (1, 4).
[openTriangle moveToPoint:NSMakePoint(rect.origin.x + 1, rect.origin.y + 4 + 8)];
[openTriangle lineToPoint:NSMakePoint(rect.origin.x + 1 + 9, rect.origin.y + 4 + 8)];
[openTriangle lineToPoint:NSMakePoint(rect.origin.x + 1 + 4.5, rect.origin.y + 4)];
[openTriangle closePath];
[openTriangle fill];
}
}
void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const
{ {
QPainterPath focusRingPath; QPainterPath focusRingPath;
@ -3301,15 +3241,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
CGContextScaleCTM(cg, 1, -1); CGContextScaleCTM(cg, 1, -1);
CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y); CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave && !qt_mac_applicationIsInDarkMode()) { [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
// When the real system theme is one of the 'Dark' themes, and an application forces the 'Aqua' theme,
// under some conditions (see QTBUG-74515 for more details) NSButtonCell seems to select the 'Dark'
// code path and is becoming transparent, thus 'invisible' on the white background. To workaround this,
// we draw the disclose triangle manually:
qt_drawDisclosureButton(cg, triangleCell.state, (opt->state & State_Selected) && viewHasFocus, rect);
} else {
[triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
}
d->restoreNSGraphicsContext(cg); d->restoreNSGraphicsContext(cg);
break; } break; }

View File

@ -11343,7 +11343,7 @@ void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter)
} }
// sourceRect must be in the given coordinate system // sourceRect must be in the given coordinate system
QRect QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const QRectF QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const
{ {
QRectF effectRectF; QRectF effectRectF;
@ -11371,7 +11371,7 @@ QRect QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem sy
*unpadded = true; *unpadded = true;
} }
return effectRectF.toAlignedRect(); return effectRectF;
} }
QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset, QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset,
@ -11389,7 +11389,8 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP
bool unpadded; bool unpadded;
const QRectF sourceRect = boundingRect(system); const QRectF sourceRect = boundingRect(system);
QRect effectRect = paddedEffectRect(system, mode, sourceRect, &unpadded); QRectF effectRectF = paddedEffectRect(system, mode, sourceRect, &unpadded);
QRect effectRect = effectRectF.toAlignedRect();
if (offset) if (offset)
*offset = effectRect.topLeft(); *offset = effectRect.topLeft();
@ -11405,7 +11406,9 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP
if (effectRect.isEmpty()) if (effectRect.isEmpty())
return QPixmap(); return QPixmap();
QPixmap pixmap(effectRect.size()); const auto dpr = info ? info->painter->device()->devicePixelRatioF() : 1.0;
QPixmap pixmap(QRectF(effectRectF.topLeft(), effectRectF.size() * dpr).toAlignedRect().size());
pixmap.setDevicePixelRatio(dpr);
pixmap.fill(Qt::transparent); pixmap.fill(Qt::transparent);
QPainter pixmapPainter(&pixmap); QPainter pixmapPainter(&pixmap);
pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing); pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing);

View File

@ -644,7 +644,7 @@ public:
QPixmap pixmap(Qt::CoordinateSystem system, QPixmap pixmap(Qt::CoordinateSystem system,
QPoint *offset, QPoint *offset,
QGraphicsEffect::PixmapPadMode mode) const override; QGraphicsEffect::PixmapPadMode mode) const override;
QRect paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded = nullptr) const; QRectF paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded = nullptr) const;
QGraphicsItem *item; QGraphicsItem *item;
QGraphicsItemPaintInfo *info; QGraphicsItemPaintInfo *info;

View File

@ -4852,7 +4852,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
&& painter->worldTransform().type() <= QTransform::TxTranslate) && painter->worldTransform().type() <= QTransform::TxTranslate)
{ {
QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates); QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates);
QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect); QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect).toAlignedRect();
sourced->setCachedOffset(effectRect.topLeft()); sourced->setCachedOffset(effectRect.topLeft());
} else { } else {

View File

@ -2283,13 +2283,15 @@ void QHeaderViewPrivate::_q_sectionsChanged(const QList<QPersistentModelIndex> &
: index.row()); : index.row());
// the new visualIndices are already adjusted / reset by initializeSections() // the new visualIndices are already adjusted / reset by initializeSections()
const int newVisualIndex = visualIndex(newLogicalIndex); const int newVisualIndex = visualIndex(newLogicalIndex);
auto &newSection = sectionItems[newVisualIndex]; if (newVisualIndex < sectionItems.count()) {
newSection = item.section; auto &newSection = sectionItems[newVisualIndex];
newSection = item.section;
if (newSection.isHidden) { if (newSection.isHidden) {
// otherwise setSectionHidden will return without doing anything // otherwise setSectionHidden will return without doing anything
newSection.isHidden = false; newSection.isHidden = false;
q->setSectionHidden(newLogicalIndex, true); q->setSectionHidden(newLogicalIndex, true);
}
} }
} }

View File

@ -650,11 +650,13 @@ QListWidgetItem::QListWidgetItem(const QString &text, QListWidget *listview, int
|Qt::ItemIsEnabled |Qt::ItemIsEnabled
|Qt::ItemIsDragEnabled) |Qt::ItemIsDragEnabled)
{ {
QListModel *model = listModel();
{ {
QSignalBlocker b(view); QSignalBlocker b(view);
QSignalBlocker bm(model);
setData(Qt::DisplayRole, text); setData(Qt::DisplayRole, text);
} }
if (QListModel *model = listModel()) if (model)
model->insert(model->rowCount(), this); model->insert(model->rowCount(), this);
} }
@ -683,12 +685,14 @@ QListWidgetItem::QListWidgetItem(const QIcon &icon,const QString &text,
|Qt::ItemIsEnabled |Qt::ItemIsEnabled
|Qt::ItemIsDragEnabled) |Qt::ItemIsDragEnabled)
{ {
QListModel *model = listModel();
{ {
QSignalBlocker b(view); QSignalBlocker b(view);
QSignalBlocker bm(model);
setData(Qt::DisplayRole, text); setData(Qt::DisplayRole, text);
setData(Qt::DecorationRole, icon); setData(Qt::DecorationRole, icon);
} }
if (QListModel *model = listModel()) if (model)
model->insert(model->rowCount(), this); model->insert(model->rowCount(), this);
} }

View File

@ -1448,7 +1448,8 @@ bool QOpenGLWidget::event(QEvent *e)
{ {
// Special case: did grabFramebuffer() for a hidden widget that then became visible. // Special case: did grabFramebuffer() for a hidden widget that then became visible.
// Recreate all resources since the context now needs to share with the TLW's. // Recreate all resources since the context now needs to share with the TLW's.
d->reset(); if (!qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts))
d->reset();
} }
if (!d->initialized && !size().isEmpty() && window()->windowHandle()) { if (!d->initialized && !size().isEmpty() && window()->windowHandle()) {
d->initialize(); d->initialize();

View File

@ -2908,7 +2908,10 @@ void QStyleSheetStyle::polish(QPalette &pal)
void QStyleSheetStyle::repolish(QWidget *w) void QStyleSheetStyle::repolish(QWidget *w)
{ {
QList<const QObject *> children = w->findChildren<const QObject *>(QString()); QList<const QObject *> children;
children.reserve(w->children().size() + 1);
for (auto child: qAsConst(w->children()))
children.append(child);
children.append(w); children.append(w);
styleSheetCaches->styleSheetCache.remove(w); styleSheetCaches->styleSheetCache.remove(w);
updateObjects(children); updateObjects(children);

View File

@ -69,6 +69,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QSystemTrayIconSys; class QSystemTrayIconSys;
class QSystemTrayWatcher;
class QPlatformSystemTrayIcon; class QPlatformSystemTrayIcon;
class QToolButton; class QToolButton;
class QLabel; class QLabel;
@ -90,6 +91,8 @@ public:
void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon, void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon,
QSystemTrayIcon::MessageIcon msgIcon, int msecs); QSystemTrayIcon::MessageIcon msgIcon, int msecs);
void destroyIcon();
static bool isSystemTrayAvailable_sys(); static bool isSystemTrayAvailable_sys();
static bool supportsMessages_sys(); static bool supportsMessages_sys();
@ -101,6 +104,7 @@ public:
QSystemTrayIconSys *sys; QSystemTrayIconSys *sys;
QPlatformSystemTrayIcon *qpa_sys; QPlatformSystemTrayIcon *qpa_sys;
bool visible; bool visible;
QSystemTrayWatcher *trayWatcher;
private: private:
void install_sys_qpa(); void install_sys_qpa();

View File

@ -92,9 +92,6 @@ protected:
virtual void resizeEvent(QResizeEvent *) override; virtual void resizeEvent(QResizeEvent *) override;
virtual void moveEvent(QMoveEvent *) override; virtual void moveEvent(QMoveEvent *) override;
private slots:
void systemTrayWindowChanged(QScreen *screen);
private: private:
QSystemTrayIcon *q; QSystemTrayIcon *q;
}; };
@ -116,15 +113,6 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn)
setMouseTracking(true); setMouseTracking(true);
} }
void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *)
{
if (!locateSystemTray()) {
QBalloonTip::hideBalloon();
hide(); // still no luck
destroy();
}
}
QRect QSystemTrayIconSys::globalGeometry() const QRect QSystemTrayIconSys::globalGeometry() const
{ {
return QRect(mapToGlobal(QPoint(0, 0)), size()); return QRect(mapToGlobal(QPoint(0, 0)), size());
@ -199,10 +187,41 @@ void QSystemTrayIconSys::resizeEvent(QResizeEvent *event)
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
class QSystemTrayWatcher: public QObject
{
Q_OBJECT
public:
QSystemTrayWatcher(QSystemTrayIcon *trayIcon)
: QObject(trayIcon)
, mTrayIcon(trayIcon)
{
// This code uses string-based syntax because we want to connect to a signal
// which is defined in XCB plugin - QXcbNativeInterface::systemTrayWindowChanged().
connect(qGuiApp->platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)),
this, SLOT(systemTrayWindowChanged(QScreen*)));
}
private slots:
void systemTrayWindowChanged(QScreen *)
{
auto icon = static_cast<QSystemTrayIconPrivate *>(QObjectPrivate::get(mTrayIcon));
icon->destroyIcon();
if (icon->visible && locateSystemTray()) {
icon->sys = new QSystemTrayIconSys(mTrayIcon);
icon->sys->show();
}
}
private:
QSystemTrayIcon *mTrayIcon = nullptr;
};
////////////////////////////////////////////////////////////////////////////
QSystemTrayIconPrivate::QSystemTrayIconPrivate() QSystemTrayIconPrivate::QSystemTrayIconPrivate()
: sys(0), : sys(0),
qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()), qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()),
visible(false) visible(false),
trayWatcher(nullptr)
{ {
} }
@ -213,16 +232,21 @@ QSystemTrayIconPrivate::~QSystemTrayIconPrivate()
void QSystemTrayIconPrivate::install_sys() void QSystemTrayIconPrivate::install_sys()
{ {
Q_Q(QSystemTrayIcon);
if (qpa_sys) { if (qpa_sys) {
install_sys_qpa(); install_sys_qpa();
return; return;
} }
Q_Q(QSystemTrayIcon);
if (!sys && locateSystemTray()) { if (!sys) {
sys = new QSystemTrayIconSys(q); if (!trayWatcher)
QObject::connect(QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)), trayWatcher = new QSystemTrayWatcher(q);
sys, SLOT(systemTrayWindowChanged(QScreen*)));
sys->show(); if (locateSystemTray()) {
sys = new QSystemTrayIconSys(q);
sys->show();
}
} }
} }
@ -241,14 +265,21 @@ void QSystemTrayIconPrivate::remove_sys()
remove_sys_qpa(); remove_sys_qpa();
return; return;
} }
destroyIcon();
}
void QSystemTrayIconPrivate::destroyIcon()
{
if (!sys) if (!sys)
return; return;
QBalloonTip::hideBalloon(); QBalloonTip::hideBalloon();
sys->hide(); // this should do the trick, but... sys->hide();
delete sys; // wm may resize system tray only for DestroyEvents delete sys;
sys = 0; sys = nullptr;
} }
void QSystemTrayIconPrivate::updateIcon_sys() void QSystemTrayIconPrivate::updateIcon_sys()
{ {
if (qpa_sys) { if (qpa_sys) {

View File

@ -1239,6 +1239,8 @@ void QPlainTextEditPrivate::ensureViewportLayouted()
This property gets and sets the plain text editor's contents. The previous This property gets and sets the plain text editor's contents. The previous
contents are removed and undo/redo history is reset when this property is set. contents are removed and undo/redo history is reset when this property is set.
currentCharFormat() is also reset, unless textCursor() is already at the
beginning of the document.
By default, for an editor with no contents, this property contains an empty string. By default, for an editor with no contents, this property contains an empty string.
*/ */
@ -1518,7 +1520,12 @@ void QPlainTextEdit::paste()
/*! /*!
Deletes all the text in the text edit. Deletes all the text in the text edit.
Note that the undo/redo history is cleared by this function. Notes:
\list
\li The undo/redo history is also cleared.
\li currentCharFormat() is reset, unless textCursor()
is already at the beginning of the document.
\endlist
\sa cut(), setPlainText() \sa cut(), setPlainText()
*/ */
@ -1651,7 +1658,12 @@ void QPlainTextEdit::timerEvent(QTimerEvent *e)
\a text is interpreted as plain text. \a text is interpreted as plain text.
Note that the undo/redo history is cleared by this function. Notes:
\list
\li The undo/redo history is also cleared.
\li currentCharFormat() is reset, unless textCursor()
is already at the beginning of the document.
\endlist
\sa toPlainText() \sa toPlainText()
*/ */

View File

@ -556,7 +556,8 @@ void QTextEditPrivate::_q_ensureVisible(const QRectF &_rect)
This property gets and sets the text editor's contents as plain This property gets and sets the text editor's contents as plain
text. Previous contents are removed and undo/redo history is reset text. Previous contents are removed and undo/redo history is reset
when the property is set. when the property is set. currentCharFormat() is also reset, unless
textCursor() is already at the beginning of the document.
If the text edit has another content type, it will not be replaced If the text edit has another content type, it will not be replaced
by plain text if you call toPlainText(). The only exception to this by plain text if you call toPlainText(). The only exception to this
@ -1034,7 +1035,12 @@ void QTextEdit::paste()
/*! /*!
Deletes all the text in the text edit. Deletes all the text in the text edit.
Note that the undo/redo history is cleared by this function. Notes:
\list
\li The undo/redo history is also cleared.
\li currentCharFormat() is reset, unless textCursor()
is already at the beginning of the document.
\endlist
\sa cut(), setPlainText(), setHtml() \sa cut(), setPlainText(), setHtml()
*/ */
@ -1139,9 +1145,13 @@ void QTextEdit::timerEvent(QTimerEvent *e)
Changes the text of the text edit to the string \a text. Changes the text of the text edit to the string \a text.
Any previous text is removed. Any previous text is removed.
\a text is interpreted as plain text. Notes:
\list
Note that the undo/redo history is cleared by this function. \li \a text is interpreted as plain text.
\li The undo/redo history is also cleared.
\li currentCharFormat() is reset, unless textCursor()
is already at the beginning of the document.
\endlist
\sa toPlainText() \sa toPlainText()
*/ */
@ -1175,7 +1185,8 @@ QString QTextEdit::toPlainText() const
setHtml() changes the text of the text edit. Any previous text is setHtml() changes the text of the text edit. Any previous text is
removed and the undo/redo history is cleared. The input text is removed and the undo/redo history is cleared. The input text is
interpreted as rich text in html format. interpreted as rich text in html format. currentCharFormat() is also
reset, unless textCursor() is already at the beginning of the document.
\note It is the responsibility of the caller to make sure that the \note It is the responsibility of the caller to make sure that the
text is correctly decoded when a QString containing HTML is created text is correctly decoded when a QString containing HTML is created

View File

@ -1559,6 +1559,16 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
<< NtfsTestResource(NtfsTestResource::SymLink, relToRelSymlink, relToRelTarget) << NtfsTestResource(NtfsTestResource::SymLink, relToRelSymlink, relToRelTarget)
<< relToRelSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); << relToRelSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
} }
{
// Symlink to UNC share
pwd.mkdir("unc");
QString errorMessage;
QString uncTarget = QStringLiteral("//") + QtNetworkSettings::winServerName() + "/testshare";
QString uncSymlink = QDir::toNativeSeparators(pwd.absolutePath().append("\\unc\\link_to_unc"));
QTest::newRow("UNC symlink")
<< NtfsTestResource(NtfsTestResource::SymLink, uncSymlink, uncTarget)
<< QDir::fromNativeSeparators(uncSymlink) << true << QDir::fromNativeSeparators(uncTarget) << uncTarget;
}
//Junctions //Junctions
QString target = "target"; QString target = "target";
@ -1630,7 +1640,7 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks()
// Ensure that junctions, mountpoints are removed. If this fails, do not remove // Ensure that junctions, mountpoints are removed. If this fails, do not remove
// temporary directory to prevent it from trashing the system. // temporary directory to prevent it from trashing the system.
if (fi.isDir()) { if (fi.isDir()) {
if (!QDir().rmdir(fi.fileName())) { if (!QDir().rmdir(fi.filePath())) {
qWarning("Unable to remove NTFS junction '%s'', keeping '%s'.", qWarning("Unable to remove NTFS junction '%s'', keeping '%s'.",
qPrintable(fi.fileName()), qPrintable(QDir::toNativeSeparators(m_dir.path()))); qPrintable(fi.fileName()), qPrintable(QDir::toNativeSeparators(m_dir.path())));
m_dir.setAutoRemove(false); m_dir.setAutoRemove(false);

View File

@ -1,4 +1,5 @@
CONFIG += testcase CONFIG += testcase
qtConfig(c++14): CONFIG += c++14
TARGET = tst_qmetaobject TARGET = tst_qmetaobject
QT = core-private testlib QT = core-private testlib
SOURCES = tst_qmetaobject.cpp SOURCES = tst_qmetaobject.cpp

View File

@ -816,6 +816,15 @@ void tst_QMetaObject::invokePointer()
QCOMPARE(obj.slotResult, QString("sl1:bubu")); QCOMPARE(obj.slotResult, QString("sl1:bubu"));
} }
QCOMPARE(countedStructObjectsCount, 0); QCOMPARE(countedStructObjectsCount, 0);
#ifdef __cpp_init_captures
{
CountedStruct str;
std::unique_ptr<int> ptr( new int );
QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj, p = std::move(ptr)]() { obj.sl1(t1); }));
QCOMPARE(obj.slotResult, QString("sl1:1"));
}
QCOMPARE(countedStructObjectsCount, 0);
#endif
} }
void tst_QMetaObject::invokeQueuedMetaMember() void tst_QMetaObject::invokeQueuedMetaMember()
@ -1121,6 +1130,15 @@ void tst_QMetaObject::invokeBlockingQueuedPointer()
QCOMPARE(exp, QString("yessir")); QCOMPARE(exp, QString("yessir"));
QCOMPARE(obj.slotResult, QString("sl1:bubu")); QCOMPARE(obj.slotResult, QString("sl1:bubu"));
} }
#ifdef __cpp_init_captures
{
std::unique_ptr<int> ptr(new int);
QVERIFY(QMetaObject::invokeMethod(&obj,
[&obj, p = std::move(ptr)]() { return obj.sl1("hehe"); },
Qt::BlockingQueuedConnection));
QCOMPARE(obj.slotResult, QString("sl1:hehe"));
}
#endif
QVERIFY(QMetaObject::invokeMethod(&obj, [&](){obj.moveToThread(QThread::currentThread());}, Qt::BlockingQueuedConnection)); QVERIFY(QMetaObject::invokeMethod(&obj, [&](){obj.moveToThread(QThread::currentThread());}, Qt::BlockingQueuedConnection));
t.quit(); t.quit();
QVERIFY(t.wait()); QVERIFY(t.wait());

View File

@ -78,9 +78,11 @@ private slots:
void toString_isoDate_data(); void toString_isoDate_data();
void toString_isoDate(); void toString_isoDate();
void toString_isoDate_extra(); void toString_isoDate_extra();
#if QT_CONFIG(datestring)
void toString_textDate_data(); void toString_textDate_data();
void toString_textDate(); void toString_textDate();
void toString_textDate_extra(); void toString_textDate_extra();
#endif
void toString_rfcDate_data(); void toString_rfcDate_data();
void toString_rfcDate(); void toString_rfcDate();
void toString_enumformat(); void toString_enumformat();
@ -800,11 +802,11 @@ void tst_QDateTime::toString_isoDate_data()
QTest::newRow("positive OffsetFromUTC") QTest::newRow("positive OffsetFromUTC")
<< dt << Qt::ISODate << dt << Qt::ISODate
<< QString("1978-11-09T13:28:34+05:30"); << QString("1978-11-09T13:28:34+05:30");
dt.setUtcOffset(-7200); dt.setOffsetFromUtc(-7200);
QTest::newRow("negative OffsetFromUTC") QTest::newRow("negative OffsetFromUTC")
<< dt << Qt::ISODate << dt << Qt::ISODate
<< QString("1978-11-09T13:28:34-02:00"); << QString("1978-11-09T13:28:34-02:00");
dt.setUtcOffset(-900); dt.setOffsetFromUtc(-900);
QTest::newRow("negative non-integral OffsetFromUTC") QTest::newRow("negative non-integral OffsetFromUTC")
<< dt << Qt::ISODate << dt << Qt::ISODate
<< QString("1978-11-09T13:28:34-00:15"); << QString("1978-11-09T13:28:34-00:15");
@ -840,7 +842,7 @@ void tst_QDateTime::toString_isoDate()
QCOMPARE(resultDatetime.date(), datetime.date()); QCOMPARE(resultDatetime.date(), datetime.date());
QCOMPARE(resultDatetime.time(), datetime.time()); QCOMPARE(resultDatetime.time(), datetime.time());
QCOMPARE(resultDatetime.timeSpec(), datetime.timeSpec()); QCOMPARE(resultDatetime.timeSpec(), datetime.timeSpec());
QCOMPARE(resultDatetime.utcOffset(), datetime.utcOffset()); QCOMPARE(resultDatetime.offsetFromUtc(), datetime.offsetFromUtc());
} else { } else {
QCOMPARE(resultDatetime, QDateTime()); QCOMPARE(resultDatetime, QDateTime());
} }
@ -870,12 +872,14 @@ void tst_QDateTime::toString_isoDate_extra()
#endif // timezone #endif // timezone
} }
#if QT_CONFIG(datestring)
void tst_QDateTime::toString_textDate_data() void tst_QDateTime::toString_textDate_data()
{ {
QTest::addColumn<QDateTime>("datetime"); QTest::addColumn<QDateTime>("datetime");
QTest::addColumn<QString>("expected"); QTest::addColumn<QString>("expected");
QString wednesdayJanuary = QDate::shortDayName(3) + ' ' + QDate::shortMonthName(1); QString wednesdayJanuary = QLocale::system().dayName(3, QLocale::ShortFormat)
+ ' ' + QLocale::system().monthName(1, QLocale::ShortFormat);
QTest::newRow("localtime") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::LocalTime) QTest::newRow("localtime") << QDateTime(QDate(2013, 1, 2), QTime(1, 2, 3), Qt::LocalTime)
<< wednesdayJanuary + QString(" 2 01:02:03 2013"); << wednesdayJanuary + QString(" 2 01:02:03 2013");
@ -904,7 +908,7 @@ void tst_QDateTime::toString_textDate()
QCOMPARE(resultDatetime.date(), datetime.date()); QCOMPARE(resultDatetime.date(), datetime.date());
QCOMPARE(resultDatetime.time(), datetime.time()); QCOMPARE(resultDatetime.time(), datetime.time());
QCOMPARE(resultDatetime.timeSpec(), datetime.timeSpec()); QCOMPARE(resultDatetime.timeSpec(), datetime.timeSpec());
QCOMPARE(resultDatetime.utcOffset(), datetime.utcOffset()); QCOMPARE(resultDatetime.offsetFromUtc(), datetime.offsetFromUtc());
} }
void tst_QDateTime::toString_textDate_extra() void tst_QDateTime::toString_textDate_extra()
@ -953,6 +957,7 @@ void tst_QDateTime::toString_textDate_extra()
dt = QDateTime::fromMSecsSinceEpoch(0, Qt::UTC); dt = QDateTime::fromMSecsSinceEpoch(0, Qt::UTC);
QVERIFY(dt.toString().endsWith(GMT)); QVERIFY(dt.toString().endsWith(GMT));
} }
#endif // datestring
void tst_QDateTime::toString_rfcDate_data() void tst_QDateTime::toString_rfcDate_data()
{ {
@ -968,11 +973,11 @@ void tst_QDateTime::toString_rfcDate_data()
<< QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC) << QDateTime(QDate(1978, 11, 9), QTime(13, 28, 34), Qt::UTC)
<< QString("09 Nov 1978 13:28:34 +0000"); << QString("09 Nov 1978 13:28:34 +0000");
QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34)); QDateTime dt(QDate(1978, 11, 9), QTime(13, 28, 34));
dt.setUtcOffset(19800); dt.setOffsetFromUtc(19800);
QTest::newRow("positive OffsetFromUTC") QTest::newRow("positive OffsetFromUTC")
<< dt << dt
<< QString("09 Nov 1978 13:28:34 +0530"); << QString("09 Nov 1978 13:28:34 +0530");
dt.setUtcOffset(-7200); dt.setOffsetFromUtc(-7200);
QTest::newRow("negative OffsetFromUTC") QTest::newRow("negative OffsetFromUTC")
<< dt << dt
<< QString("09 Nov 1978 13:28:34 -0200"); << QString("09 Nov 1978 13:28:34 -0200");

View File

@ -35,11 +35,13 @@
namespace namespace
{ {
QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion) QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion,
QShaderFormat::ShaderType shaderType= QShaderFormat::Fragment)
{ {
auto format = QShaderFormat(); auto format = QShaderFormat();
format.setApi(api); format.setApi(api);
format.setVersion(QVersionNumber(majorVersion, minorVersion)); format.setVersion(QVersionNumber(majorVersion, minorVersion));
format.setShaderType(shaderType);
return format; return format;
} }
@ -74,7 +76,7 @@ namespace
return edge; return edge;
} }
QShaderGraph createGraph() QShaderGraph createFragmentShaderGraph()
{ {
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0); const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
@ -194,6 +196,7 @@ private slots:
void shouldProcessLanguageQualifierAndTypeEnums_data(); void shouldProcessLanguageQualifierAndTypeEnums_data();
void shouldProcessLanguageQualifierAndTypeEnums(); void shouldProcessLanguageQualifierAndTypeEnums();
void shouldGenerateDifferentCodeDependingOnActiveLayers(); void shouldGenerateDifferentCodeDependingOnActiveLayers();
void shouldUseGlobalVariableRatherThanTemporaries();
}; };
void tst_QShaderGenerator::shouldHaveDefaultState() void tst_QShaderGenerator::shouldHaveDefaultState()
@ -213,7 +216,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
QTest::addColumn<QShaderFormat>("format"); QTest::addColumn<QShaderFormat>("format");
QTest::addColumn<QByteArray>("expectedCode"); QTest::addColumn<QByteArray>("expectedCode");
const auto graph = createGraph(); const auto graph = createFragmentShaderGraph();
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0); const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
@ -234,14 +237,9 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< " highp vec2 v2 = texCoord;" << " highp vec4 v5 = texture2D(texture, texCoord);"
<< " sampler2D v1 = texture;" << " highp vec4 v6 = lightModel(v5, worldPosition, lightIntensity);"
<< " highp float v3 = lightIntensity;" << " highp vec4 v7 = v6 * pow(2.0, exposure);"
<< " highp vec4 v5 = texture2D(v1, v2);"
<< " highp vec3 v0 = worldPosition;"
<< " highp float v4 = exposure;"
<< " highp vec4 v6 = lightModel(v5, v0, v3);"
<< " highp vec4 v7 = v6 * pow(2.0, v4);"
<< " gl_fragColor = v7;" << " gl_fragColor = v7;"
<< "}" << "}"
<< ""; << "";
@ -256,14 +254,9 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< " vec2 v2 = texCoord;" << " vec4 v5 = texture2D(texture, texCoord);"
<< " sampler2D v1 = texture;" << " vec4 v6 = lightModel(v5, worldPosition, lightIntensity);"
<< " float v3 = lightIntensity;" << " vec4 v7 = v6 * pow(2.0, exposure);"
<< " vec4 v5 = texture2D(v1, v2);"
<< " vec3 v0 = worldPosition;"
<< " float v4 = exposure;"
<< " vec4 v6 = lightModel(v5, v0, v3);"
<< " vec4 v7 = v6 * pow(2.0, v4);"
<< " fragColor = v7;" << " fragColor = v7;"
<< "}" << "}"
<< ""; << "";
@ -580,120 +573,190 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
QTest::addColumn<QShaderFormat>("format"); QTest::addColumn<QShaderFormat>("format");
QTest::addColumn<QByteArray>("expectedCode"); QTest::addColumn<QByteArray>("expectedCode");
const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0); {
const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0); const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0); const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0);
const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0);
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0);
const auto qualifierEnum = QMetaEnum::fromType<QShaderLanguage::StorageQualifier>(); const auto qualifierEnum = QMetaEnum::fromType<QShaderLanguage::StorageQualifier>();
const auto typeEnum = QMetaEnum::fromType<QShaderLanguage::VariableType>(); const auto typeEnum = QMetaEnum::fromType<QShaderLanguage::VariableType>();
for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) { for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) {
const auto qualifierName = qualifierEnum.key(qualifierIndex); const auto qualifierName = qualifierEnum.key(qualifierIndex);
const auto qualifierValue = static_cast<QShaderLanguage::StorageQualifier>(qualifierEnum.value(qualifierIndex)); const auto qualifierValue = static_cast<QShaderLanguage::StorageQualifier>(qualifierEnum.value(qualifierIndex));
for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) { for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) {
const auto typeName = typeEnum.key(typeIndex); const auto typeName = typeEnum.key(typeIndex);
const auto typeValue = static_cast<QShaderLanguage::VariableType>(typeEnum.value(typeIndex)); const auto typeValue = static_cast<QShaderLanguage::VariableType>(typeEnum.value(typeIndex));
auto graph = QShaderGraph();
auto worldPosition = createNode({
createPort(QShaderNodePort::Output, "value")
});
worldPosition.setParameter("name", "worldPosition");
worldPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(qualifierValue));
worldPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(typeValue));
worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;",
QByteArrayList() << "$qualifier highp $type $name;"));
worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;",
QByteArrayList() << "$qualifier $type $name;"));
worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;",
QByteArrayList() << "$qualifier $type $name;"));
auto fragColor = createNode({
createPort(QShaderNodePort::Input, "fragColor")
});
fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;",
QByteArrayList() << "out vec4 fragColor;"));
graph.addNode(worldPosition);
graph.addNode(fragColor);
graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor"));
const auto gl2Code = (QByteArrayList() << "#version 110"
<< ""
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2))
.arg(toGlsl(typeValue))
.toUtf8()
<< ""
<< "void main()"
<< "{"
<< " gl_fragColor = worldPosition;"
<< "}"
<< "").join("\n");
const auto gl3Code = (QByteArrayList() << "#version 130"
<< ""
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3))
.arg(toGlsl(typeValue))
.toUtf8()
<< "out vec4 fragColor;"
<< ""
<< "void main()"
<< "{"
<< " fragColor = worldPosition;"
<< "}"
<< "").join("\n");
const auto gl4Code = (QByteArrayList() << "#version 400 core"
<< ""
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4))
.arg(toGlsl(typeValue))
.toUtf8()
<< "out vec4 fragColor;"
<< ""
<< "void main()"
<< "{"
<< " fragColor = worldPosition;"
<< "}"
<< "").join("\n");
const auto es2Code = (QByteArrayList() << "#version 100"
<< ""
<< QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2))
.arg(toGlsl(typeValue))
.toUtf8()
<< ""
<< "void main()"
<< "{"
<< " gl_fragColor = worldPosition;"
<< "}"
<< "").join("\n");
const auto es3Code = (QByteArrayList() << "#version 300 es"
<< ""
<< QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3))
.arg(toGlsl(typeValue))
.toUtf8()
<< ""
<< "void main()"
<< "{"
<< " gl_fragColor = worldPosition;"
<< "}"
<< "").join("\n");
QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code;
QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code;
QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code;
QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code;
QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code;
}
}
}
{
const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0, QShaderFormat::Vertex);
const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0, QShaderFormat::Vertex);
const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0, QShaderFormat::Vertex);
const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, QShaderFormat::Vertex);
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0, QShaderFormat::Vertex);
auto graph = QShaderGraph(); auto graph = QShaderGraph();
auto worldPosition = createNode({ auto vertexPosition = createNode({
createPort(QShaderNodePort::Output, "value") createPort(QShaderNodePort::Output, "value")
}); });
worldPosition.setParameter("name", "worldPosition"); vertexPosition.setParameter("name", "vertexPosition");
worldPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(qualifierValue)); vertexPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(QShaderLanguage::Input));
worldPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(typeValue)); vertexPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(QShaderLanguage::Vec4));
worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;",
vertexPosition.addRule(es2, QShaderNode::Rule("",
QByteArrayList() << "$qualifier highp $type $name;")); QByteArrayList() << "$qualifier highp $type $name;"));
worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;", vertexPosition.addRule(gl2, QShaderNode::Rule("",
QByteArrayList() << "$qualifier $type $name;")); QByteArrayList() << "$qualifier $type $name;"));
worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;", vertexPosition.addRule(gl3, QShaderNode::Rule("",
QByteArrayList() << "$qualifier $type $name;")); QByteArrayList() << "$qualifier $type $name;"));
auto fragColor = createNode({ graph.addNode(vertexPosition);
createPort(QShaderNodePort::Input, "fragColor")
});
fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;",
QByteArrayList() << "out vec4 fragColor;"));
graph.addNode(worldPosition);
graph.addNode(fragColor);
graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor"));
const auto gl2Code = (QByteArrayList() << "#version 110" const auto gl2Code = (QByteArrayList() << "#version 110"
<< "" << ""
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2)) << "attribute vec4 vertexPosition;"
.arg(toGlsl(typeValue))
.toUtf8()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " gl_fragColor = v0;"
<< "}" << "}"
<< "").join("\n"); << "").join("\n");
const auto gl3Code = (QByteArrayList() << "#version 130" const auto gl3Code = (QByteArrayList() << "#version 130"
<< "" << ""
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3)) << "in vec4 vertexPosition;"
.arg(toGlsl(typeValue))
.toUtf8()
<< "out vec4 fragColor;"
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " fragColor = v0;"
<< "}" << "}"
<< "").join("\n"); << "").join("\n");
const auto gl4Code = (QByteArrayList() << "#version 400 core" const auto gl4Code = (QByteArrayList() << "#version 400 core"
<< "" << ""
<< QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4)) << "in vec4 vertexPosition;"
.arg(toGlsl(typeValue))
.toUtf8()
<< "out vec4 fragColor;"
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " fragColor = v0;"
<< "}" << "}"
<< "").join("\n"); << "").join("\n");
const auto es2Code = (QByteArrayList() << "#version 100" const auto es2Code = (QByteArrayList() << "#version 100"
<< "" << ""
<< QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2)) << "attribute highp vec4 vertexPosition;"
.arg(toGlsl(typeValue))
.toUtf8()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " gl_fragColor = v0;"
<< "}" << "}"
<< "").join("\n"); << "").join("\n");
const auto es3Code = (QByteArrayList() << "#version 300 es" const auto es3Code = (QByteArrayList() << "#version 300 es"
<< "" << ""
<< QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3)) << "in highp vec4 vertexPosition;"
.arg(toGlsl(typeValue))
.toUtf8()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " gl_fragColor = v0;"
<< "}" << "}"
<< "").join("\n"); << "").join("\n");
QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code; QTest::addRow("Attribute header substitution ES2") << graph << es2 << es2Code;
QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code; QTest::addRow("Attribute header substitution ES3") << graph << es3 << es3Code;
QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code; QTest::addRow("Attribute header substitution GL2") << graph << gl2 << gl2Code;
QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code; QTest::addRow("Attribute header substitution GL3") << graph << gl3 << gl3Code;
QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code; QTest::addRow("Attribute header substitution GL4") << graph << gl4 << gl4Code;
}
} }
} }
@ -806,9 +869,7 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< " vec3 v1 = normalUniform;" << " vec4 v2 = lightModel(diffuseUniform, normalUniform);"
<< " vec4 v0 = diffuseUniform;"
<< " vec4 v2 = lightModel(v0, v1);"
<< " fragColor = v2;" << " fragColor = v2;"
<< "}" << "}"
<< ""; << "";
@ -831,10 +892,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< " vec2 v0 = texCoord;" << " vec3 v2 = texture2D(normalTexture, texCoord).rgb;"
<< " vec3 v2 = texture2D(normalTexture, v0).rgb;" << " vec4 v3 = lightModel(diffuseUniform, v2);"
<< " vec4 v1 = diffuseUniform;"
<< " vec4 v3 = lightModel(v1, v2);"
<< " fragColor = v3;" << " fragColor = v3;"
<< "}" << "}"
<< ""; << "";
@ -857,10 +916,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< " vec2 v0 = texCoord;" << " vec4 v1 = texture2D(diffuseTexture, texCoord);"
<< " vec3 v2 = normalUniform;" << " vec4 v3 = lightModel(v1, normalUniform);"
<< " vec4 v1 = texture2D(diffuseTexture, v0);"
<< " vec4 v3 = lightModel(v1, v2);"
<< " fragColor = v3;" << " fragColor = v3;"
<< "}" << "}"
<< ""; << "";
@ -883,9 +940,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< "" << ""
<< "void main()" << "void main()"
<< "{" << "{"
<< " vec2 v0 = texCoord;" << " vec3 v2 = texture2D(normalTexture, texCoord).rgb;"
<< " vec3 v2 = texture2D(normalTexture, v0).rgb;" << " vec4 v1 = texture2D(diffuseTexture, texCoord);"
<< " vec4 v1 = texture2D(diffuseTexture, v0);"
<< " vec4 v3 = lightModel(v1, v2);" << " vec4 v3 = lightModel(v1, v2);"
<< " fragColor = v3;" << " fragColor = v3;"
<< "}" << "}"
@ -894,6 +950,133 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
} }
} }
void tst_QShaderGenerator::shouldUseGlobalVariableRatherThanTemporaries()
{
// GIVEN
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0);
{
// WHEN
auto vertexPosition = createNode({
createPort(QShaderNodePort::Output, "vertexPosition")
});
vertexPosition.addRule(gl4, QShaderNode::Rule("vec4 $vertexPosition = vertexPosition;",
QByteArrayList() << "in vec4 vertexPosition;"));
auto fakeMultiPlyNoSpace = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeMultiPlyNoSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName*v11;"));
auto fakeMultiPlySpace = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeMultiPlySpace.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName * v11;"));
auto fakeJoinNoSpace = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeJoinNoSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = vec4($varName.xyz,$varName.w);"));
auto fakeJoinSpace = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeJoinSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = vec4($varName.xyz, $varName.w);"));
auto fakeAdd = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeAdd.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName.xyzw + $varName;"));
auto fakeSub = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeSub.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName.xyzw - $varName;"));
auto fakeDiv = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeDiv.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName / v0;"));
auto fragColor = createNode({
createPort(QShaderNodePort::Input, "input1"),
createPort(QShaderNodePort::Input, "input2"),
createPort(QShaderNodePort::Input, "input3"),
createPort(QShaderNodePort::Input, "input4"),
createPort(QShaderNodePort::Input, "input5"),
createPort(QShaderNodePort::Input, "input6"),
createPort(QShaderNodePort::Input, "input7")
});
fragColor.addRule(gl4, QShaderNode::Rule("fragColor = $input1 + $input2 + $input3 + $input4 + $input5 + $input6 + $input7;",
QByteArrayList() << "out vec4 fragColor;"));
const auto graph = [=] {
auto res = QShaderGraph();
res.addNode(vertexPosition);
res.addNode(fakeMultiPlyNoSpace);
res.addNode(fakeMultiPlySpace);
res.addNode(fakeJoinNoSpace);
res.addNode(fakeJoinSpace);
res.addNode(fakeAdd);
res.addNode(fakeSub);
res.addNode(fakeDiv);
res.addNode(fragColor);
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeMultiPlyNoSpace.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeMultiPlySpace.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeJoinNoSpace.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeJoinSpace.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeAdd.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeSub.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeDiv.uuid(), "varName"));
res.addEdge(createEdge(fakeMultiPlyNoSpace.uuid(), "out", fragColor.uuid(), "input1"));
res.addEdge(createEdge(fakeMultiPlySpace.uuid(), "out", fragColor.uuid(), "input2"));
res.addEdge(createEdge(fakeJoinNoSpace.uuid(), "out", fragColor.uuid(), "input3"));
res.addEdge(createEdge(fakeJoinSpace.uuid(), "out", fragColor.uuid(), "input4"));
res.addEdge(createEdge(fakeAdd.uuid(), "out", fragColor.uuid(), "input5"));
res.addEdge(createEdge(fakeSub.uuid(), "out", fragColor.uuid(), "input6"));
res.addEdge(createEdge(fakeDiv.uuid(), "out", fragColor.uuid(), "input7"));
return res;
}();
auto generator = QShaderGenerator();
generator.graph = graph;
generator.format = gl4;
const auto code = generator.createShaderCode({"diffuseUniform", "normalUniform"});
// THEN
const auto expected = QByteArrayList()
<< "#version 400 core"
<< ""
<< "in vec4 vertexPosition;"
<< "out vec4 fragColor;"
<< ""
<< "void main()"
<< "{"
<< " vec4 v7 = vertexPosition / vertexPosition;"
<< " vec4 v6 = vertexPosition.xyzw - vertexPosition;"
<< " vec4 v5 = vertexPosition.xyzw + vertexPosition;"
<< " vec4 v4 = vec4(vertexPosition.xyz, vertexPosition.w);"
<< " vec4 v3 = vec4(vertexPosition.xyz,vertexPosition.w);"
<< " vec4 v2 = vertexPosition * v11;"
<< " vec4 v1 = vertexPosition*v11;"
<< " fragColor = v1 + v2 + v3 + v4 + v5 + v6 + v7;"
<< "}"
<< "";
QCOMPARE(code, expected.join("\n"));
}
}
QTEST_MAIN(tst_QShaderGenerator) QTEST_MAIN(tst_QShaderGenerator)
#include "tst_qshadergenerator.moc" #include "tst_qshadergenerator.moc"

View File

@ -248,6 +248,7 @@ private slots:
void sizeHintCrash(); void sizeHintCrash();
void testResetCachedSizeHint(); void testResetCachedSizeHint();
void statusTips(); void statusTips();
void testRemovingColumnsViaLayoutChanged();
protected: protected:
void setupTestData(bool use_reset_model = false); void setupTestData(bool use_reset_model = false);
@ -353,6 +354,7 @@ public:
void cleanup() void cleanup()
{ {
emit layoutAboutToBeChanged();
cols = 3; cols = 3;
rows = 3; rows = 3;
emit layoutChanged(); emit layoutChanged();
@ -3489,5 +3491,20 @@ void tst_QHeaderView::statusTips()
QCOMPARE(headerView.statusTipText, QLatin1String("[0,1,0] -- Header")); QCOMPARE(headerView.statusTipText, QLatin1String("[0,1,0] -- Header"));
} }
void tst_QHeaderView::testRemovingColumnsViaLayoutChanged()
{
const int persistentSectionSize = 101;
QtTestModel model;
model.rows = model.cols = 5;
view->setModel(&model);
for (int i = 0; i < model.cols; ++i)
view->resizeSection(i, persistentSectionSize + i);
model.cleanup(); // down to 3 via layoutChanged (not columnsRemoved)
for (int j = 0; j < model.cols; ++j)
QCOMPARE(view->sectionSize(j), persistentSectionSize + j);
// The main point of this test is that the section-size restoring code didn't go out of bounds.
}
QTEST_MAIN(tst_QHeaderView) QTEST_MAIN(tst_QHeaderView)
#include "tst_qheaderview.moc" #include "tst_qheaderview.moc"

View File

@ -267,6 +267,7 @@ tst_QListWidget::tst_QListWidget(): testWidget(0), rcParent(8), rcFirst(8,0), rc
void tst_QListWidget::initTestCase() void tst_QListWidget::initTestCase()
{ {
qRegisterMetaType<QListWidgetItem*>("QListWidgetItem*");
testWidget = new QListWidget(); testWidget = new QListWidget();
testWidget->show(); testWidget->show();
@ -663,6 +664,9 @@ void tst_QListWidget::insertItems()
QFETCH(int, rowCount); QFETCH(int, rowCount);
QFETCH(int, insertType); QFETCH(int, insertType);
QSignalSpy itemChangedSpy(testWidget, &QListWidget::itemChanged);
QSignalSpy dataChangedSpy(testWidget->model(), &QAbstractItemModel::dataChanged);
if (insertType == 3) { if (insertType == 3) {
QStringList strings; QStringList strings;
for (int i=0; i<rowCount; ++i) for (int i=0; i<rowCount; ++i)
@ -700,6 +704,9 @@ void tst_QListWidget::insertItems()
// make sure all items have view set correctly // make sure all items have view set correctly
for (int i=0; i<testWidget->count(); ++i) for (int i=0; i<testWidget->count(); ++i)
QCOMPARE(testWidget->item(i)->listWidget(), testWidget); QCOMPARE(testWidget->item(i)->listWidget(), testWidget);
QCOMPARE(itemChangedSpy.count(), 0);
QCOMPARE(dataChangedSpy.count(), 0);
} }
void tst_QListWidget::itemAssignment() void tst_QListWidget::itemAssignment()
@ -1257,7 +1264,6 @@ void tst_QListWidget::setData()
QFETCH(IntList, roles); QFETCH(IntList, roles);
QFETCH(QVariantList, values); QFETCH(QVariantList, values);
QFETCH(int, expectedSignalCount); QFETCH(int, expectedSignalCount);
qRegisterMetaType<QListWidgetItem *>("QListWidgetItem*");
QCOMPARE(roles.count(), values.count()); QCOMPARE(roles.count(), values.count());
@ -1715,7 +1721,6 @@ void tst_QListWidget::task258949_keypressHangup()
void tst_QListWidget::QTBUG8086_currentItemChangedOnClick() void tst_QListWidget::QTBUG8086_currentItemChangedOnClick()
{ {
qRegisterMetaType<QListWidgetItem*>("QListWidgetItem*");
QWidget win; QWidget win;
QHBoxLayout layout(&win); QHBoxLayout layout(&win);
QListWidget list; QListWidget list;
@ -1837,7 +1842,6 @@ void tst_QListWidget::mimeData()
void tst_QListWidget::QTBUG50891_ensureSelectionModelSignalConnectionsAreSet() void tst_QListWidget::QTBUG50891_ensureSelectionModelSignalConnectionsAreSet()
{ {
qRegisterMetaType<QListWidgetItem*>("QListWidgetItem*");
QListWidget list; QListWidget list;
for (int i = 0 ; i < 4; ++i) for (int i = 0 ; i < 4; ++i)
new QListWidgetItem(QString::number(i), &list); new QListWidgetItem(QString::number(i), &list);

View File

@ -46,3 +46,6 @@ osx
osx-10.12 ci osx-10.12 ci
[multipleToplevelFocusCheck] [multipleToplevelFocusCheck]
linux linux
[windowState]
# QTBUG-75270
winrt

View File

@ -48,6 +48,7 @@ public:
private slots: private slots:
void init(); void init();
void repolish(); void repolish();
void repolish_without_crashing();
void numinstances(); void numinstances();
void widgetsBeforeAppStyleSheet(); void widgetsBeforeAppStyleSheet();
void widgetsAfterAppStyleSheet(); void widgetsAfterAppStyleSheet();
@ -367,6 +368,26 @@ void tst_QStyleSheetStyle::repolish()
QCOMPARE(BACKGROUND(p1), APPBACKGROUND(p1)); QCOMPARE(BACKGROUND(p1), APPBACKGROUND(p1));
} }
void tst_QStyleSheetStyle::repolish_without_crashing()
{
// This used to crash, QTBUG-69204
QMainWindow w;
QScopedPointer<QSplitter> splitter1(new QSplitter(w.centralWidget()));
QScopedPointer<QSplitter> splitter2(new QSplitter);
QScopedPointer<QSplitter> splitter3(new QSplitter);
splitter2->addWidget(splitter3.data());
splitter2->setStyleSheet("color: red");
QScopedPointer<QLabel> label(new QLabel);
label->setTextFormat(Qt::RichText);
splitter3->addWidget(label.data());
label->setText("hey");
splitter1->addWidget(splitter2.data());
w.show();
QCOMPARE(COLOR(*label), QColor(Qt::red));
}
void tst_QStyleSheetStyle::widgetStyle() void tst_QStyleSheetStyle::widgetStyle()
{ {
qApp->setStyleSheet(QString()); qApp->setStyleSheet(QString());

View File

@ -90,15 +90,15 @@ int main(int argc, char **argv)
{ {
QCoreApplication app(argc, argv); QCoreApplication app(argc, argv);
if (argc < 3) { if (argc < 3) {
printf("\nusage: %s inputFile outputFile\n\n", argv[0]); printf("\nUsage: ./%s inputFile outputFile\n\n", argv[0]);
printf("'inputFile' should be a list of effective TLDs, one per line,\n"); printf("'inputFile' should be a list of effective TLDs, one per line,\n");
printf("as obtained from http://publicsuffix.org . To create indices and data file\n"); printf("as obtained from http://publicsuffix.org/. To create indices and data\n");
printf("file, do the following:\n\n"); printf("file, do the following:\n\n");
printf(" wget https://publicsuffix.org/list/effective_tld_names.dat -O effective_tld_names.dat\n"); printf(" wget https://publicsuffix.org/list/public_suffix_list.dat -O public_suffix_list.dat\n");
printf(" grep '^[^\\/\\/]' effective_tld_names.dat > effective_tld_names.dat.trimmed\n"); printf(" grep -v '^//' public_suffix_list.dat | grep . > public_suffix_list.dat.trimmed\n");
printf(" %s effective_tld_names.dat.trimmed effective_tld_names.dat.qt\n\n", argv[0]); printf(" ./%s public_suffix_list.dat.trimmed public_suffix_list.cpp\n\n", argv[0]);
printf("Now copy the data from effective_tld_names.dat.qt to the file src/corelib/io/qurltlds_p.h in your Qt repo\n\n"); printf("Now replace the code in qtbase/src/corelib/io/qurltlds_p.h with public_suffix_list.cpp's contents\n\n");
exit(1); return 1;
} }
QFile file(argv[1]); QFile file(argv[1]);
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {