From 2afc8e3ad67989644576f232187003ba0c6b7a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 12 Jan 2018 14:16:43 +0100 Subject: [PATCH 001/146] Add bearer plugin removal notice to changelog Task-number: QTBUG-40332 Change-Id: Ie975ad86a235ccfff0c3f72bb108b6fa9a89ad13 Reviewed-by: Timur Pocheptsov --- dist/changes-5.9.4 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dist/changes-5.9.4 b/dist/changes-5.9.4 index 0bb768424fa..f0cc6007c22 100644 --- a/dist/changes-5.9.4 +++ b/dist/changes-5.9.4 @@ -65,6 +65,12 @@ QtCore QtNetwork --------- + - Bearer Management: + * [QTBUG-40332] The nativewifi (Windows) bearer plugin was determined + to be causing network interference in the form of system-wide higher + latency and has been disabled. The CoreWlan (macOS) plugin has also + been disabled. + - QUdpSocket: * [QTBUG-64718] Fixed a regression from Qt 5.9.3 caused by an apparent Win32 API quirk we triggered when using readDatagram(), resulting in From 0d9208cecbbd9ed08e4ffb6540729668e3bd7754 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 15 Jan 2018 12:59:22 -0800 Subject: [PATCH 002/146] QMacStyle: Revert state changes for PE_IndicatorMenuCheckMark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The changes introduced in 0e810e27a5e5a6c2e244ca439fbdf4f4ccc5b3da turn out to be incompatible with our style sheets styling. We partially revert the style option state check, so that the look for a highlighted PE_IndicatorMenuCheckMark only depends on State_On, as it's expected in QWindowsStyle and QCommonStyle. [ChangeLog][QtWidgets][QMacStyle] PE_IndicatorMenuCheckMark goes back to only depend on State_On for its highlighted look. Change-Id: I20f8e712196b5515bd5528ff6eedcdca9df5856f Task-number: QTBUG-65773 Reviewed-by: Thorbjørn Lund Martsum --- src/widgets/styles/qmacstyle_mac.mm | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index f45bf7011f7..e6436f82a64 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -3389,13 +3389,12 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai } break; case PE_IndicatorMenuCheckMark: { - if (!(opt->state & State_On)) - break; QColor pc; - if (opt->state & State_Selected) + if (opt->state & State_On) pc = opt->palette.highlightedText().color(); else pc = opt->palette.text().color(); + QCFType checkmarkColor = CGColorCreateGenericRGB(static_cast(pc.redF()), static_cast(pc.greenF()), static_cast(pc.blueF()), @@ -4493,8 +4492,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter const int xp = contentRect.x() + macItemFrame; checkmarkOpt.rect = QRect(xp, contentRect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh); - checkmarkOpt.state |= State_On; // Always on. Never rendered when off. - checkmarkOpt.state.setFlag(State_Selected, active); + checkmarkOpt.state.setFlag(State_On, active); checkmarkOpt.state.setFlag(State_Enabled, enabled); if (widgetSize == QAquaSizeMini) checkmarkOpt.state |= State_Mini; From 9de2ef6f5ab3b21b4e1679e010ee488193cb41e4 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 16 Jan 2018 08:23:55 +0100 Subject: [PATCH 003/146] QWidget: Fix a crash when platform window creation fails Add a check on the platform window to QWidgetPrivate::create_sys(). Task-number: QTBUG-65783 Change-Id: I077882e1cf22ef49bb6f578f7460493ef48c9627 Reviewed-by: Richard Moe Gustavsen --- src/widgets/kernel/qwidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index b38565493e1..1fea3836ec5 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1480,7 +1480,8 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO if (q->windowType() != Qt::Desktop || q->testAttribute(Qt::WA_NativeWindow)) { win->create(); // Enable nonclient-area events for QDockWidget and other NonClientArea-mouse event processing. - win->handle()->setFrameStrutEventsEnabled(true); + if (QPlatformWindow *platformWindow = win->handle()) + platformWindow->setFrameStrutEventsEnabled(true); } data.window_flags = win->flags(); From 40e87491886957696486b87dc2dedec2adaf6e1a Mon Sep 17 00:00:00 2001 From: Alexander Shevchenko Date: Wed, 10 Jan 2018 17:51:54 +0200 Subject: [PATCH 004/146] unify windows mkspecs: update definitions mingw-w64 toolchain: - add missing compiler definitions, similar to 'msvc-desktop.conf' toolchain, - describe the reasons of missing compiler definitions, available in 'msvc-desktop.conf' toolchain, - add missing 'QMAKE_CXXFLAGS' and 'QMAKE_CXXFLAGS_WARN_ON' variables, similar to 'msvc-desktop.conf' toolchain. ICC on Windows toolchain: - add 'QMAKE_CFLAGS_OPTIMIZE_FULL' variable, similar to 'gcc-base.conf' toolchain, though left it unused for now, - add missing flags to 'QMAKE_CFLAGS' variable, similar to 'msvc-desktop.conf' toolchain, - update deprecated 'Qwd' flag with 'Qdiag-disable', - use 'QMAKE_CFLAGS_OPTIMIZE_DEBUG' variable instead of '-Od' flag, similar to 'gcc-base.conf' toolchain (ICC implies '-O2' optimization level by default, while MSVC implies '-Od'), - add 'QMAKE_CFLAGS_UTF8_SOURCE' variable, similar to 'msvc-version.conf' toolchain; use a workaround to initialize it, until '-utf-8' flag would be supported by ICC on Windows, - update deprecated '-Qstd=c++1z' flag with '-Qstd=c++17', MSVC toolchain: - remove 'incremental' from MSVC 'CONFIG' variable, since it has relevance only for the Unix generator, - add 'QMAKE_CFLAGS_OPTIMIZE_DEBUG' variable, used in ICC for Windows toolchain, - add empty 'QMAKE_LIBS' variable, similar to 'win32-g++' toolchain, - add 'uuid.lib' library to 'QMAKE_LIBS_GUI' variable, similar to 'win32-g++' toolchain, - add C++14 and C++17 language support flags, though left them disabled for now, similar to 'win32-icc' toolchain. Change-Id: Ideef62d0422674184836faa655bfc5d09a5f612f Reviewed-by: Joerg Bornemann Reviewed-by: Kai Koehne Reviewed-by: Oswald Buddenhagen --- mkspecs/common/msvc-desktop.conf | 6 ++++-- mkspecs/common/msvc-version.conf | 5 +++++ mkspecs/win32-g++/qmake.conf | 9 +++++++-- mkspecs/win32-icc/qmake.conf | 15 +++++++++------ 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf index 496ca1179dd..546b9cf3cb8 100644 --- a/mkspecs/common/msvc-desktop.conf +++ b/mkspecs/common/msvc-desktop.conf @@ -15,7 +15,7 @@ MAKEFILE_GENERATOR = MSVC.NET QMAKE_PLATFORM = win32 QMAKE_COMPILER = msvc -CONFIG += incremental flat debug_and_release debug_and_release_target precompile_header autogen_precompile_source embed_manifest_dll embed_manifest_exe +CONFIG += flat debug_and_release debug_and_release_target precompile_header autogen_precompile_source embed_manifest_dll embed_manifest_exe DEFINES += UNICODE _UNICODE WIN32 QMAKE_COMPILER_DEFINES += _WIN32 contains(QMAKE_TARGET.arch, x86_64) { @@ -23,6 +23,7 @@ contains(QMAKE_TARGET.arch, x86_64) { QMAKE_COMPILER_DEFINES += _WIN64 } +QMAKE_CFLAGS_OPTIMIZE_DEBUG = -Od QMAKE_CFLAGS_OPTIMIZE = -O2 QMAKE_CFLAGS_OPTIMIZE_SIZE = -O1 @@ -92,7 +93,8 @@ QMAKE_EXTENSION_SHLIB = dll QMAKE_PREFIX_STATICLIB = QMAKE_EXTENSION_STATICLIB = lib -QMAKE_LIBS_GUI = gdi32.lib comdlg32.lib oleaut32.lib imm32.lib winmm.lib ws2_32.lib ole32.lib user32.lib advapi32.lib +QMAKE_LIBS = +QMAKE_LIBS_GUI = gdi32.lib comdlg32.lib oleaut32.lib imm32.lib winmm.lib ws2_32.lib ole32.lib uuid.lib user32.lib advapi32.lib QMAKE_LIBS_NETWORK = ws2_32.lib QMAKE_LIBS_OPENGL = glu32.lib opengl32.lib gdi32.lib user32.lib QMAKE_LIBS_OPENGL_ES2 = gdi32.lib user32.lib diff --git a/mkspecs/common/msvc-version.conf b/mkspecs/common/msvc-version.conf index ba74c49f9c7..cfafb06305e 100644 --- a/mkspecs/common/msvc-version.conf +++ b/mkspecs/common/msvc-version.conf @@ -85,6 +85,11 @@ greaterThan(QMAKE_MSC_VER, 1909) { # API is used in direct2d, but also in multimedia, positioning and sensors. # We can try again with a later version of Visual Studio. # QMAKE_CXXFLAGS_STRICTCXX = -permissive- + # MSVC partially supports the following, but '__cplusplus' definition is set + # as for C++98 until MSVC fully conforms with C++14, see + # https://developercommunity.visualstudio.com/content/problem/139261/msvc-incorrectly-defines-cplusplus.html + # QMAKE_CXXFLAGS_CXX14 = -std:c++14 + # QMAKE_CXXFLAGS_CXX1Z = -std:c++latest } greaterThan(QMAKE_MSC_VER, 1910) { diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf index a4955e99f30..96c94e7021e 100644 --- a/mkspecs/win32-g++/qmake.conf +++ b/mkspecs/win32-g++/qmake.conf @@ -16,8 +16,11 @@ include(../common/g++-base.conf) MAKEFILE_GENERATOR = MINGW QMAKE_PLATFORM = win32 mingw CONFIG += debug_and_release debug_and_release_target precompile_header -DEFINES += UNICODE _UNICODE -QMAKE_COMPILER_DEFINES += __GNUC__ WIN32 +DEFINES += UNICODE _UNICODE WIN32 +QMAKE_COMPILER_DEFINES += __GNUC__ _WIN32 +# can't add 'DEFINES += WIN64' and 'QMAKE_COMPILER_DEFINES += _WIN64' defines for +# x86_64 platform similar to 'msvc-desktop.conf' toolchain, because, unlike for MSVC, +# 'QMAKE_TARGET.arch' is inherently unavailable. QMAKE_CC = $${CROSS_COMPILE}gcc QMAKE_LEX = flex @@ -30,6 +33,8 @@ QMAKE_CFLAGS_WARN_ON += -Wextra QMAKE_CFLAGS_SSE2 += -mstackrealign QMAKE_CXX = $${CROSS_COMPILE}g++ +QMAKE_CXXFLAGS = $$QMAKE_CFLAGS +QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON QMAKE_CXXFLAGS_RTTI_ON = -frtti QMAKE_CXXFLAGS_RTTI_OFF = -fno-rtti QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions -mthreads diff --git a/mkspecs/win32-icc/qmake.conf b/mkspecs/win32-icc/qmake.conf index 4d18b1cc55e..c66d73383a2 100644 --- a/mkspecs/win32-icc/qmake.conf +++ b/mkspecs/win32-icc/qmake.conf @@ -4,7 +4,7 @@ # Written for Intel C++ Compiler on Windows / icl 16.0 or higher # -# Use the Microsoft (R) C/C++ Optimizing Compiler configuration, +# Use the Microsoft C/C++ Optimizing Compiler configuration, # since ICC on Windows pretends to be MSVC include(../common/msvc-desktop.conf) @@ -13,11 +13,14 @@ include(../common/msvc-desktop.conf) QMAKE_COMPILER += intel_icl +QMAKE_CFLAGS_OPTIMIZE_FULL = -O3 + QMAKE_CC = icl -QMAKE_CFLAGS = -nologo -Zm200 /Qprec /Qwd1744,1738,809,3373 -QMAKE_CFLAGS_WARN_ON = -W3 /Qwd673 -QMAKE_CFLAGS_WARN_OFF = -W0 /Qwd673 -QMAKE_CFLAGS_DEBUG = -Od -Zi -MDd +QMAKE_CFLAGS = -nologo -Zc:wchar_t -Qprec -Zm200 -Qdiag-disable:1744,1738,809,3373 +QMAKE_CFLAGS_WARN_ON = -W3 -Qdiag-disable:673 +QMAKE_CFLAGS_WARN_OFF = -W0 -Qdiag-disable:673 +QMAKE_CFLAGS_DEBUG = $$QMAKE_CFLAGS_OPTIMIZE_DEBUG -Zi -MDd +QMAKE_CFLAGS_UTF8_SOURCE = -Qoption,cpp,--unicode_source_kind,UTF-8 QMAKE_CFLAGS_LTCG = -Qipo QMAKE_CFLAGS_DISABLE_LTCG = -Qno-ipo @@ -44,7 +47,7 @@ QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF QMAKE_CXXFLAGS_CXX11 = -Qstd=c++11 # ICC supports the following but Qt won't compile #QMAKE_CXXFLAGS_CXX14 = -Qstd=c++14 -#QMAKE_CXXFLAGS_CXX1Z = -Qstd=c++1z +#QMAKE_CXXFLAGS_CXX1Z = -Qstd=c++17 QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG QMAKE_CXXFLAGS_DISABLE_LTCG = $$QMAKE_CFLAGS_DISABLE_LTCG From 8c023326c79b4fdb7eaa26600b1af622f5bce318 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 11 Jan 2018 12:26:32 +0100 Subject: [PATCH 005/146] config_help.txt: document that some sanitize combinations are not valid Saves people the trouble of trying it out themselves. When I tried "address" and "thread", I got: cc1plus: error: -fsanitize=address and -fsanitize=kernel-address are incompatible with -fsanitize=thread Change-Id: I48ae817e60d0b71d5349e1dbce8706cc8430c2c4 Reviewed-by: Edward Welbourne Reviewed-by: Oswald Buddenhagen --- config_help.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config_help.txt b/config_help.txt index 9c424391a91..0bb440b5560 100644 --- a/config_help.txt +++ b/config_help.txt @@ -121,6 +121,9 @@ Build options: -gcov ................ Instrument with the GCov code coverage tool [no] -sanitize {address|thread|memory|undefined} Instrument with the specified compiler sanitizer. + Note that some sanitizers cannot be combined; + for example, -sanitize address cannot be combined with + -sanitize thread. -c++std .... Select C++ standard [c++1z/c++14/c++11] (Not supported with MSVC) From a57585961823cfc4d9a20ffd5dde3520c9229d61 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Wed, 17 Jan 2018 20:56:34 +0100 Subject: [PATCH 006/146] QThreadPool: Add missing semicolon after class in documentation Makes it easier to copy and paste the snippet into a code editor. Change-Id: I27c0a7aa268bd4fd0af885e929f67a28f083dabf Reviewed-by: Thiago Macieira --- .../doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp b/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp index a1372976ae8..ba31972aa12 100644 --- a/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp @@ -55,7 +55,7 @@ class HelloWorldTask : public QRunnable { qDebug() << "Hello world from thread" << QThread::currentThread(); } -} +}; HelloWorldTask *hello = new HelloWorldTask(); // QThreadPool takes ownership and deletes 'hello' automatically From 1aae404a4cf7f92d4135c1b24a3b6efef6c54708 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Tue, 18 Oct 2016 12:36:23 +0200 Subject: [PATCH 007/146] QProcess/Windows: Include PID in pipe names Although qt_create_pipe() tries again if the pipe name is already in use, it doesn't handle the case when another user has created the pipe with the name (the error is "access denied" in that case). The chance that it happens is small, but it can be entirely eliminated by including a unique part in the pipe name, in this case the PID. [ChangeLog][Windows] Named pipes internally created by QProcess now contain the PID in their name to ensure uniqueness. Change-Id: I079f1b68695c1ddea3eccad241061d11e08b60f4 Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- src/corelib/io/qprocess_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index 05c9d6594c4..fa9efcb1ce5 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -102,7 +102,7 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe) // ### The user must make sure to call qsrand() to make the pipe names less predictable. // ### Replace the call to qrand() with a secure version, once we have it in Qt. _snwprintf(pipeName, sizeof(pipeName) / sizeof(pipeName[0]), - L"\\\\.\\pipe\\qt-%X", qrand()); + L"\\\\.\\pipe\\qt-%lX-%X", long(QCoreApplication::applicationPid()), qrand()); DWORD dwOpenMode = FILE_FLAG_OVERLAPPED; DWORD dwOutputBufferSize = 0; From 2b47afadc0fcc9a2617d5c9e8be0ee035762e0b9 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Wed, 12 Jul 2017 17:15:10 +0200 Subject: [PATCH 008/146] gtk3: Disable native file dialogs on GTK3 < 3.15.5 Showing file dialogs if running on a system that has an older GTK3 version installed results in a crash. Do a version check at runtime and disable native file dialog support if the version is too old. (GTK3 bug: https://bugzilla.gnome.org/show_bug.cgi?id=725164) Change-Id: I77bd23f1298333412bae04f52153e1a224ddf470 Reviewed-by: Oswald Buddenhagen Reviewed-by: J-P Nurmi Reviewed-by: Dmitry Shachnev --- src/plugins/platformthemes/gtk3/qgtk3theme.cpp | 17 ++++++++++++++++- src/plugins/platformthemes/gtk3/qgtk3theme.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp index 6447776f253..077955eb4e2 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp +++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp @@ -153,7 +153,7 @@ bool QGtk3Theme::usePlatformNativeDialog(DialogType type) const case ColorDialog: return true; case FileDialog: - return true; + return useNativeFileDialog(); case FontDialog: return true; default: @@ -167,6 +167,8 @@ QPlatformDialogHelper *QGtk3Theme::createPlatformDialogHelper(DialogType type) c case ColorDialog: return new QGtk3ColorDialogHelper; case FileDialog: + if (!useNativeFileDialog()) + return nullptr; return new QGtk3FileDialogHelper; case FontDialog: return new QGtk3FontDialogHelper; @@ -185,4 +187,17 @@ QPlatformMenuItem* QGtk3Theme::createPlatformMenuItem() const return new QGtk3MenuItem; } +bool QGtk3Theme::useNativeFileDialog() +{ + /* Require GTK3 >= 3.15.5 to avoid running into this bug: + * https://bugzilla.gnome.org/show_bug.cgi?id=725164 + * + * While this bug only occurs when using widget-based file dialogs + * (native GTK3 dialogs are fine) we have to disable platform file + * dialogs entirely since we can't avoid creation of a platform + * dialog helper. + */ + return gtk_check_version(3, 15, 5) == 0; +} + QT_END_NAMESPACE diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.h b/src/plugins/platformthemes/gtk3/qgtk3theme.h index 52036680c65..abc5dbfd175 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3theme.h +++ b/src/plugins/platformthemes/gtk3/qgtk3theme.h @@ -59,6 +59,8 @@ public: QPlatformMenuItem* createPlatformMenuItem() const Q_DECL_OVERRIDE; static const char *name; +private: + static bool useNativeFileDialog(); }; QT_END_NAMESPACE From bed6292dde5c9a017a7cac7be6948471949174e8 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 7 Dec 2017 14:49:44 +0100 Subject: [PATCH 009/146] Win: Document limitation regarding registry types not being preserved QSettings does not preserve the original key type in the registry, it will set the type for the key based on the value that is being set. Therefore we should make it clear that existing key types will be overridden as this can cause some problems with types we do not directly support (such as REG_EXPAND_SZ). Task-number: QTBUG-2894 Change-Id: Ib2f2eed02759591e69fefb98a4a1f3cf897dd5cb Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qsettings.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index d5460238ecb..9b930e7e144 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -2358,6 +2358,11 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, limitations is to store the settings using the IniFormat instead of the NativeFormat. + \li On Windows, when the Windows system registry is used, QSettings + does not preserve the original type of the value. Therefore, + the type of the value might change when a new value is set. For + example, a value with type \c REG_EXPAND_SZ will change to \c REG_SZ. + \li On \macos and iOS, allKeys() will return some extra keys for global settings that apply to all applications. These keys can be read using value() but cannot be changed, only shadowed. From 3149d0fb13bacc20b75ad8ca650c71df9edd8734 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 18 Jan 2018 12:51:21 +0100 Subject: [PATCH 010/146] use correct path separators when invoking testcases on windows Change-Id: Iad541f0d62ffdb2751da6225b9d40229d7d9a03f Reviewed-by: Joerg Bornemann Reviewed-by: Edward Welbourne --- mkspecs/features/testcase.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/testcase.prf b/mkspecs/features/testcase.prf index 3e1537dde0a..8d51c9d028c 100644 --- a/mkspecs/features/testcase.prf +++ b/mkspecs/features/testcase.prf @@ -44,7 +44,7 @@ unix { $${type}.commands += $${TEST_TARGET_DIR}/$(QMAKE_TARGET) } else { # Windows - !isEmpty(TEST_TARGET_DIR): TEST_TARGET_DIR = $${TEST_TARGET_DIR}$${QMAKE_DIR_SEP} + !isEmpty(TEST_TARGET_DIR): TEST_TARGET_DIR = $$shell_path($$TEST_TARGET_DIR)$${QMAKE_DIR_SEP} $${type}.commands += $${TEST_TARGET_DIR}$(TARGET) } From e86f3c018833141776db2d15772ba53995656eac Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 28 Jul 2017 13:25:27 +0200 Subject: [PATCH 011/146] qmake: require a drive in a DOS path for it to be absolute For Q_OS_WIN, a path is only truly absolute if it includes a drive letter; merely starting with a slash is not enough. (We can't support UNC paths, so don't even try: qmake runs various commands in the source directory using CMD.exe, which doesn't support UNC as PWD.) This requires, when resolving a path relative to a root, transcribing the root's drive to such not-quite-absolute paths. Changed QMakeGlobals, $$absolute_path() and $$relative_path() to now use IoUtils::resolvePath() rather than delegating to QDir's absolute path method, since that doesn't correctly recognize the need for a drive letter (and qmake did run into problems with some paths, from splitPathList and a failing test, as a result). Moved existing ioUtils tests for handling of relative / absolute paths out into separate functions and expanded significantly. Fixed some existing tests to use an absolute path where one is needed; added two tests involving driveless (but rooted) paths; and fixed the test init to set a value for QT_HOST_DATA/src property (the lack of which lead to an assertion failure with this fix). Task-number: QTBUG-50839 Change-Id: I2bfc13c1bfbe1ae09997274622ea55cb3de31b43 Reviewed-by: Oswald Buddenhagen --- qmake/library/ioutils.cpp | 23 +++-- qmake/library/qmakebuiltins.cpp | 13 +-- qmake/library/qmakeglobals.cpp | 15 ++-- tests/auto/tools/qmakelib/evaltest.cpp | 46 +++++++--- tests/auto/tools/qmakelib/tst_qmakelib.cpp | 97 ++++++++++++++++++++-- tests/auto/tools/qmakelib/tst_qmakelib.h | 5 ++ 6 files changed, 157 insertions(+), 42 deletions(-) diff --git a/qmake/library/ioutils.cpp b/qmake/library/ioutils.cpp index 684bcb9a371..afd41912fee 100644 --- a/qmake/library/ioutils.cpp +++ b/qmake/library/ioutils.cpp @@ -66,21 +66,22 @@ IoUtils::FileType IoUtils::fileType(const QString &fileName) bool IoUtils::isRelativePath(const QString &path) { - if (path.startsWith(QLatin1Char('/'))) - return false; #ifdef QMAKE_BUILTIN_PRFS if (path.startsWith(QLatin1String(":/"))) return false; #endif #ifdef Q_OS_WIN - if (path.startsWith(QLatin1Char('\\'))) - return false; - // Unlike QFileInfo, this won't accept a relative path with a drive letter. - // Such paths result in a royal mess anyway ... + // Unlike QFileInfo, this considers only paths with both a drive prefix and + // a subsequent (back-)slash absolute: if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter() - && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) + && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) { return false; -#endif + } + // (... unless, of course, they're UNC, which qmake fails on anyway) +#else + if (path.startsWith(QLatin1Char('/'))) + return false; +#endif // Q_OS_WIN return true; } @@ -100,6 +101,12 @@ QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName) return QString(); if (isAbsolutePath(fileName)) return QDir::cleanPath(fileName); +#ifdef Q_OS_WIN // Add drive to otherwise-absolute path: + if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') { + Q_ASSERT(isAbsolutePath(baseDir)); + return QDir::cleanPath(baseDir.left(2) + fileName); + } +#endif // Q_OS_WIN return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName); } diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index 1b98cbd909a..e4b00a6cb35 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -1173,9 +1173,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( if (args.count() > 2) { evalError(fL1S("absolute_path(path[, base]) requires one or two arguments.")); } else { - QString rstr = QDir::cleanPath( - QDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory()) - .absoluteFilePath(args.at(0).toQString(m_tmp1))); + QString arg = args.at(0).toQString(m_tmp1); + QString baseDir = args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory(); + QString rstr = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : args.count() > 1 && rstr.isSharedWith(m_tmp2) @@ -1187,9 +1187,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( if (args.count() > 2) { evalError(fL1S("relative_path(path[, base]) requires one or two arguments.")); } else { - QDir baseDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory()); - QString rstr = baseDir.relativeFilePath(baseDir.absoluteFilePath( - args.at(0).toQString(m_tmp1))); + QString arg = args.at(0).toQString(m_tmp1); + QString baseDir = args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory(); + QString absArg = arg.isEmpty() ? baseDir : IoUtils::resolvePath(baseDir, arg); + QString rstr = QDir(baseDir).relativeFilePath(absArg); ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0))); } break; diff --git a/qmake/library/qmakeglobals.cpp b/qmake/library/qmakeglobals.cpp index b6dc8b20b66..d733d479cf0 100644 --- a/qmake/library/qmakeglobals.cpp +++ b/qmake/library/qmakeglobals.cpp @@ -68,6 +68,7 @@ #endif QT_BEGIN_NAMESPACE +using namespace QMakeInternal; // for IoUtils #define fL1S(s) QString::fromLatin1(s) @@ -96,9 +97,9 @@ QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &s { QString ret = QDir::cleanPath(spec); if (ret.contains(QLatin1Char('/'))) { - QString absRet = QDir(state.pwd).absoluteFilePath(ret); + QString absRet = IoUtils::resolvePath(state.pwd, ret); if (QFile::exists(absRet)) - ret = QDir::cleanPath(absRet); + ret = absRet; } return ret; } @@ -126,10 +127,10 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( user_template_prefix = arg; break; case ArgCache: - cachefile = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg)); + cachefile = args[*pos] = IoUtils::resolvePath(state.pwd, arg); break; case ArgQtConf: - qtconf = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg)); + qtconf = args[*pos] = IoUtils::resolvePath(state.pwd, arg); break; default: if (arg.startsWith(QLatin1Char('-'))) { @@ -259,11 +260,11 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const { QStringList ret; if (!val.isEmpty()) { - QDir bdir; + QString cwd(QDir::currentPath()); const QStringList vals = val.split(dirlist_sep); ret.reserve(vals.length()); for (const QString &it : vals) - ret << QDir::cleanPath(bdir.absoluteFilePath(it)); + ret << IoUtils::resolvePath(cwd, it); } return ret; } @@ -318,7 +319,7 @@ bool QMakeGlobals::initProperties() return false; data = proc.readAll(); #else - if (FILE *proc = QT_POPEN(QString(QMakeInternal::IoUtils::shellQuote(qmake_abslocation) + if (FILE *proc = QT_POPEN(QString(IoUtils::shellQuote(qmake_abslocation) + QLatin1String(" -query")).toLocal8Bit(), QT_POPEN_READ)) { char buff[1024]; while (!feof(proc)) diff --git a/tests/auto/tools/qmakelib/evaltest.cpp b/tests/auto/tools/qmakelib/evaltest.cpp index 03fd4753fdc..cf69cc40267 100644 --- a/tests/auto/tools/qmakelib/evaltest.cpp +++ b/tests/auto/tools/qmakelib/evaltest.cpp @@ -34,6 +34,12 @@ #include #include +#ifdef Q_OS_WIN +# define EVAL_DRIVE "R:" +#else +# define EVAL_DRIVE +#endif + void tst_qmakelib::addAssignments() { QTest::newRow("assignment") @@ -1599,20 +1605,28 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir) << true; QTest::newRow("$$absolute_path(): file & path") - << "VAR = $$absolute_path(dir/file.ext, /root/sub)" - << "VAR = /root/sub/dir/file.ext" + << "VAR = $$absolute_path(dir/file.ext, " EVAL_DRIVE "/root/sub)" + << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext" << "" << true; +#ifdef Q_OS_WIN + QTest::newRow("$$absolute_path(): driveless file & absolute path") + << "VAR = $$absolute_path(/root/sub/dir/file.ext, " EVAL_DRIVE "/other)" + << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext" + << "" + << true; +#endif + QTest::newRow("$$absolute_path(): absolute file & path") - << "VAR = $$absolute_path(/root/sub/dir/file.ext, /other)" - << "VAR = /root/sub/dir/file.ext" + << "VAR = $$absolute_path(" EVAL_DRIVE "/root/sub/dir/file.ext, " EVAL_DRIVE "/other)" + << "VAR = " EVAL_DRIVE "/root/sub/dir/file.ext" << "" << true; QTest::newRow("$$absolute_path(): empty file & path") - << "VAR = $$absolute_path('', /root/sub)" - << "VAR = /root/sub" + << "VAR = $$absolute_path('', " EVAL_DRIVE "/root/sub)" + << "VAR = " EVAL_DRIVE "/root/sub" << "" << true; @@ -1634,14 +1648,22 @@ void tst_qmakelib::addReplaceFunctions(const QString &qindir) << "" << true; +#ifdef Q_OS_WIN + QTest::newRow("$$relative_path(): driveless file & absolute path") + << "VAR = $$relative_path(/root/sub/dir/file.ext, " EVAL_DRIVE "/root/sub)" + << "VAR = dir/file.ext" + << "" + << true; +#endif + QTest::newRow("$$relative_path(): absolute file & path") - << "VAR = $$relative_path(/root/sub/dir/file.ext, /root/sub)" + << "VAR = $$relative_path(" EVAL_DRIVE "/root/sub/dir/file.ext, " EVAL_DRIVE "/root/sub)" << "VAR = dir/file.ext" << "" << true; QTest::newRow("$$relative_path(): empty file & path") - << "VAR = $$relative_path('', /root/sub)" + << "VAR = $$relative_path('', " EVAL_DRIVE "/root/sub)" << "VAR = ." << "" << true; @@ -2555,20 +2577,20 @@ void tst_qmakelib::addTestFunctions(const QString &qindir) << true; QTest::newRow("touch(): missing target") - << "touch(/does/not/exist, files/other.txt): OK = 1" + << "touch(" EVAL_DRIVE "/does/not/exist, files/other.txt): OK = 1" << "OK = UNDEF" #ifdef Q_OS_WIN - << "##:1: Cannot open /does/not/exist: The system cannot find the path specified." + << "##:1: Cannot open " EVAL_DRIVE "/does/not/exist: The system cannot find the path specified." #else << "##:1: Cannot touch /does/not/exist: No such file or directory." #endif << true; QTest::newRow("touch(): missing reference") - << "touch(" + wpath + ", /does/not/exist): OK = 1" + << "touch(" + wpath + ", " EVAL_DRIVE "/does/not/exist): OK = 1" << "OK = UNDEF" #ifdef Q_OS_WIN - << "##:1: Cannot open reference file /does/not/exist: The system cannot find the path specified." + << "##:1: Cannot open reference file " EVAL_DRIVE "/does/not/exist: The system cannot find the path specified." #else << "##:1: Cannot stat() reference file /does/not/exist: No such file or directory." #endif diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.cpp b/tests/auto/tools/qmakelib/tst_qmakelib.cpp index b1250f4f1ad..4a4b20fe50d 100644 --- a/tests/auto/tools/qmakelib/tst_qmakelib.cpp +++ b/tests/auto/tools/qmakelib/tst_qmakelib.cpp @@ -42,6 +42,7 @@ void tst_qmakelib::initTestCase() #endif m_prop.insert(ProKey("P1"), ProString("prop val")); m_prop.insert(ProKey("QT_HOST_DATA/get"), ProString(m_indir)); + m_prop.insert(ProKey("QT_HOST_DATA/src"), ProString(m_indir)); QVERIFY(!m_indir.isEmpty()); QVERIFY(QDir(m_outdir).removeRecursively()); @@ -224,21 +225,99 @@ void tst_qmakelib::pathUtils() QVERIFY(IoUtils::isRelativePath(fn0)); QString fn1 = "/a/unix/file/path"; - QVERIFY(IoUtils::isAbsolutePath(fn1)); QCOMPARE(IoUtils::pathName(fn1).toString(), QStringLiteral("/a/unix/file/")); QCOMPARE(IoUtils::fileName(fn1).toString(), QStringLiteral("path")); +} -#ifdef Q_OS_WIN - QString fn0a = "c:file/path"; - QVERIFY(IoUtils::isRelativePath(fn0a)); +void tst_qmakelib::ioUtilRelativity_data() +{ + QTest::addColumn("path"); + QTest::addColumn("relative"); - QString fn1a = "c:\\file\\path"; - QVERIFY(IoUtils::isAbsolutePath(fn1a)); + static const struct { + const char *name; + const char *path; + bool relative; + } rows[] = { + { "resource", ":/resource", +#ifdef QMAKE_BUILTIN_PRFS + false +#else + true #endif + }, +#ifdef Q_OS_WIN // all the complications: + // (except UNC: unsupported) + { "drive-abs", "c:/path/to/file", false }, + { "drive-abs-bs", "c:\\path\\to\\file", false }, + { "drive-path", "c:path/to/file.txt", true }, + { "drive-path-bs", "c:path\\to\\file.txt", true }, + { "rooted", "/Users/qt/bin/true", true }, + { "rooted-bs", "\\Users\\qt\\bin\\true", true }, + { "drive-rel", "c:file.txt", true }, + { "subdir-bs", "path\\to\\file", true }, +#else + { "rooted", "/usr/bin/false", false }, +#endif // Q_OS_WIN + { "subdir", "path/to/file", true }, + { "simple", "file.name", true }, + { "empty", "", true } + }; - QString fnbase = "/another/dir"; - QCOMPARE(IoUtils::resolvePath(fnbase, fn0), QStringLiteral("/another/dir/file/path")); - QCOMPARE(IoUtils::resolvePath(fnbase, fn1), QStringLiteral("/a/unix/file/path")); + for (unsigned int i = sizeof(rows) / sizeof(rows[0]); i-- > 0; ) + QTest::newRow(rows[i].name) << QString::fromLatin1(rows[i].path) + << rows[i].relative; +} + +void tst_qmakelib::ioUtilRelativity() +{ + QFETCH(QString, path); + QFETCH(bool, relative); + + QCOMPARE(IoUtils::isRelativePath(path), relative); +} + +void tst_qmakelib::ioUtilResolve_data() +{ + QTest::addColumn("base"); + QTest::addColumn("path"); + QTest::addColumn("expect"); + + static const struct { + const char *name; + const char *base; + const char *path; + const char *expect; + } data[] = { +#ifdef Q_OS_WIN // all the complications: + { "drive-drive", "a:/ms/dir", "z:/root/file", "z:/root/file" }, + { "drive-drive-bs", "a:\\ms\\dir", "z:\\root\\file", "z:/root/file" }, + { "drive-root", "a:/ms/dir", "/root/file", "a:/root/file" }, + { "drive-root-bs", "a:\\ms\\dir", "\\root\\file", "a:/root/file" }, + { "drive-sub", "a:/ms/dir", "sub/file", "a:/ms/dir/sub/file" }, + { "drive-sub-bs", "a:\\ms\\dir", "sub\\file", "a:/ms/dir/sub/file" }, + { "drive-rel", "a:/ms/dir", "file.txt", "a:/ms/dir/file.txt" }, + { "drive-rel-bs", "a:\\ms\\dir", "file.txt", "a:/ms/dir/file.txt" }, +#else + { "abs-abs", "/a/unix/dir", "/root/file", "/root/file" }, + { "abs-sub", "/a/unix/dir", "sub/file", "/a/unix/dir/sub/file" }, + { "abs-rel", "/a/unix/dir", "file.txt", "/a/unix/dir/file.txt" }, +#endif // Q_OS_WIN + }; + + for (unsigned i = sizeof(data) / sizeof(data[0]); i-- > 0; ) + QTest::newRow(data[i].name) << QString::fromLatin1(data[i].base) + << QString::fromLatin1(data[i].path) + << QString::fromLatin1(data[i].expect); +} + +void tst_qmakelib::ioUtilResolve() +{ + QFETCH(QString, base); + QFETCH(QString, path); + QFETCH(QString, expect); + + QCOMPARE(IoUtils::resolvePath(base, path), expect); } void QMakeTestHandler::print(const QString &fileName, int lineNo, int type, const QString &msg) diff --git a/tests/auto/tools/qmakelib/tst_qmakelib.h b/tests/auto/tools/qmakelib/tst_qmakelib.h index e75dedb7ec8..acfeb43ecdb 100644 --- a/tests/auto/tools/qmakelib/tst_qmakelib.h +++ b/tests/auto/tools/qmakelib/tst_qmakelib.h @@ -48,7 +48,12 @@ private slots: void quoteArgUnix(); void quoteArgWin_data(); void quoteArgWin(); + void pathUtils(); + void ioUtilRelativity_data(); + void ioUtilRelativity(); + void ioUtilResolve_data(); + void ioUtilResolve(); void proString(); void proStringList(); From b772d9cbd786a2180f8ead923a04b537c8904ddd Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 15 Jan 2018 12:02:16 +0100 Subject: [PATCH 012/146] fix example source installation of qrc/rc files in subdirs such a project structure violates the assumption that the referenced resources are specified relative to the sub-project root, so we must resolve them to absolute paths manually. Task-number: QTBUG-65753 Change-Id: I8bcd5c6e7d7c6a713e5fcd3668be7d2f23169501 Reviewed-by: Joerg Bornemann --- mkspecs/features/qt_example_installs.prf | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/mkspecs/features/qt_example_installs.prf b/mkspecs/features/qt_example_installs.prf index 668669e4cd7..c9ce926b1a9 100644 --- a/mkspecs/features/qt_example_installs.prf +++ b/mkspecs/features/qt_example_installs.prf @@ -44,19 +44,25 @@ contains(TEMPLATE, .*app): \ for(ex, EXAMPLE_FILES): \ sourcefiles += $$files($$absolute_path($$ex, $$_PRO_FILE_PWD_)) for(res, RESOURCES) { - rfile = $$cat($$absolute_path($$res, $$_PRO_FILE_PWD_), lines) - for(rline, rfile) { + !contains(res, \\.qrc$): \ + next() + rfile = $$absolute_path($$res, $$_PRO_FILE_PWD_) + rpath = $$dirname(rfile) + rcont = $$cat($$rfile, lines) + for (rline, rcont) { resrc = $$replace(rline, ^[ \\t]*]*>([^<]+)[ \\t]*$, \\1) !equals(resrc, $$rline): \ - sourcefiles += $$resrc + sourcefiles += $$absolute_path($$resrc, $$rpath) } } for(res, RC_FILE) { - rfile = $$cat($$absolute_path($$res, $$_PRO_FILE_PWD_), lines) - for(rline, rfile) { + rfile = $$absolute_path($$res, $$_PRO_FILE_PWD_) + rpath = $$dirname(rfile) + rcont = $$cat($$rfile, lines) + for (rline, rcont) { resrc = $$replace(rline, "^\\d+\\s+ICON\\s+[^\"]*\"([^\"]+)\"\$", \\1) !equals(resrc, $$rline): \ - sourcefiles += $$resrc + sourcefiles += $$absolute_path($$resrc, $$rpath) } } sourcefiles += \ From f6f6958a3e71230d4f2ef4db54d8d7fa010fa58b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 17 Jan 2018 14:44:32 +0100 Subject: [PATCH 013/146] configure: inline D3D11_QUERY_DATA_TIMESTAMP_DISJOINT test amends a96656a8fb. Change-Id: Ic434c272bfe985ea0410090537b8a22aad3192f1 Reviewed-by: Thiago Macieira --- .../win/angle_d3d11_qdtd/angle_d3d11_qdtd.cpp | 47 ------------------- .../win/angle_d3d11_qdtd/angle_d3d11_qdtd.pro | 3 -- src/gui/configure.json | 8 +++- 3 files changed, 7 insertions(+), 51 deletions(-) delete mode 100644 config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.cpp delete mode 100644 config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.pro diff --git a/config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.cpp b/config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.cpp deleted file mode 100644 index 2dde2914a23..00000000000 --- a/config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the config.tests of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -int main(int, char**) -{ - D3D11_QUERY_DATA_TIMESTAMP_DISJOINT qdtd; - (void)qdtd; - return 0; -} diff --git a/config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.pro b/config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.pro deleted file mode 100644 index f1e530ab6e6..00000000000 --- a/config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.pro +++ /dev/null @@ -1,3 +0,0 @@ -SOURCES = angle_d3d11_qdtd.cpp -CONFIG -= qt -CONFIG += console diff --git a/src/gui/configure.json b/src/gui/configure.json index 1252dc507c2..f7377eb903e 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -595,7 +595,13 @@ "angle_d3d11_qdtd": { "label": "D3D11_QUERY_DATA_TIMESTAMP_DISJOINT", "type": "compile", - "test": "win/angle_d3d11_qdtd" + "test": { + "include": "d3d11.h", + "main": [ + "D3D11_QUERY_DATA_TIMESTAMP_DISJOINT qdtd;", + "(void) qdtd;" + ] + } }, "directwrite2": { "label": "DirectWrite 2", From 016ab238b66d84a58b665782d25daaffdf1708bd Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 7 Dec 2017 11:59:30 +0100 Subject: [PATCH 014/146] configure: express dependency of fontconfig on freetype more clearly use a "use" entry instead of including the transitive dep into the list of libraries. this also removes the redundant check of freetype features from the fontconfig test code. Change-Id: I86b78028255c9bf0a62be5ec0f97a62ef3fda36f Reviewed-by: Joerg Bornemann Reviewed-by: Thiago Macieira --- src/gui/configure.json | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/gui/configure.json b/src/gui/configure.json index f7377eb903e..1e4e56422f7 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -164,25 +164,20 @@ "label": "Fontconfig", "test": { "head": [ - "#include ", - "#include FT_FREETYPE_H", "#include ", "#ifndef FC_RGBA_UNKNOWN", "# error This version of fontconfig is tool old, it is missing the FC_RGBA_UNKNOWN define", - "#endif", - "#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) < 20110)", - "# error This version of freetype is too old.", "#endif" ], "main": [ - "FT_Face face = 0;", "FcPattern *pattern = 0;" ] }, "sources": [ - { "type": "pkgConfig", "args": "fontconfig freetype2" }, - { "type": "freetype", "libs": "-lfontconfig -lfreetype" } - ] + { "type": "pkgConfig", "args": "fontconfig" }, + { "type": "freetype", "libs": "-lfontconfig" } + ], + "use": "freetype" }, "gbm": { "label": "GBM", From f9b8ea4b0eaea94a6d724a0955b13fd8a97d96e3 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 6 Dec 2016 13:44:00 +0100 Subject: [PATCH 015/146] Fix QMacTimeZonePrivate::previousTransition() for early after epoch The native APIs don't support previous transition, only next after a stipulated date. The prior code started its search at the epoch; if used for a time before the first transition after the epoch, this found no transitions so returned invalid data, when the last transition before the epoch would have been suitable. It also wound through all transitions since the epoch, on its way to the selected time, which was potentially laborious. Instead, start a year before the stipulated time; this should get a transition if the zone uses DST. If it doesn't, start with the first known transition and binary-chop our way to one within a year of the last before the stipulated time; then wind forward one transition at a time, as before. The chopping is actually faster than binary: each time we find a transition after the interval mid-point but early enough, we move the early end of our interval to the transition, which is later than the old interval's middle. Using halving, starting with a vast interval, should thus only incur modest cost, while ensuring we give up early when no transition data is available at all or the zone's first transition ever was after the stipulated time. Task-number: QTBUG-65443 Change-Id: I96c14540fc2600837e6a22e480fb8dc36cb37220 (cherry picked from commit 7c0b706488b0edcc2fd6db7870db700ff0548f21) (cherry picked from commit a090076e93487f8e461d9b866b9da1c0c21cb59b) Reviewed-by: Andy Shaw Reviewed-by: Jason Dolan --- src/corelib/tools/qtimezoneprivate_mac.mm | 88 ++++++++++++++++++----- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/src/corelib/tools/qtimezoneprivate_mac.mm b/src/corelib/tools/qtimezoneprivate_mac.mm index 4e9a432fbfa..fa0dd87cfcf 100644 --- a/src/corelib/tools/qtimezoneprivate_mac.mm +++ b/src/corelib/tools/qtimezoneprivate_mac.mm @@ -226,27 +226,79 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinc QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const { - // No direct Mac API, so get all transitions since epoch and return the last one - QList secsList; - if (beforeMSecsSinceEpoch > 0) { - const int endSecs = beforeMSecsSinceEpoch / 1000.0; - NSTimeInterval prevSecs = 0; - NSTimeInterval nextSecs = 0; - NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs]; - // If invalid may return a nil date or an Epoch date + // The native API only lets us search forward, so we need to find an early-enough start: + const NSTimeInterval lowerBound = std::numeric_limits::min(); + const qint64 endSecs = beforeMSecsSinceEpoch / 1000; + const int year = 366 * 24 * 3600; // a (long) year, in seconds + NSTimeInterval prevSecs = endSecs; // sentinel for later check + NSTimeInterval nextSecs = prevSecs - year; + NSTimeInterval tranSecs = lowerBound; // time at a transition; may be > endSecs + + NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs]; + nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; + if (nextDate != nil + && (tranSecs = [nextDate timeIntervalSince1970]) < endSecs) { + // There's a transition within the last year before endSecs: + nextSecs = tranSecs; + } else { + // Need to start our search earlier: + nextDate = [NSDate dateWithTimeIntervalSince1970:lowerBound]; + nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; + if (nextDate != nil) { + NSTimeInterval lateSecs = nextSecs; + nextSecs = [nextDate timeIntervalSince1970]; + Q_ASSERT(nextSecs <= endSecs - year || nextSecs == tranSecs); + /* + We're looking at the first ever transition for our zone, at + nextSecs (and our zone *does* have at least one transition). If + it's later than endSecs - year, then we must have found it on the + initial check and therefore set tranSecs to the same transition + time (which, we can infer here, is >= endSecs). In this case, we + won't enter the binary-chop loop, below. + + In the loop, nextSecs < lateSecs < endSecs: we have a transition + at nextSecs and there is no transition between lateSecs and + endSecs. The loop narrows the interval between nextSecs and + lateSecs by looking for a transition after their mid-point; if it + finds one < endSecs, nextSecs moves to this transition; otherwise, + lateSecs moves to the mid-point. This soon enough narrows the gap + to within a year, after which walking forward one transition at a + time (the "Wind through" loop, below) is good enough. + */ + + // Binary chop to within a year of last transition before endSecs: + while (nextSecs + year < lateSecs) { + // Careful about overflow, not fussy about rounding errors: + NSTimeInterval middle = nextSecs / 2 + lateSecs / 2; + NSDate *split = [NSDate dateWithTimeIntervalSince1970:middle]; + split = [m_nstz nextDaylightSavingTimeTransitionAfterDate:split]; + if (split != nil + && (tranSecs = [split timeIntervalSince1970]) < endSecs) { + nextDate = split; + nextSecs = tranSecs; + } else { + lateSecs = middle; + } + } + Q_ASSERT(nextDate != nil); + // ... and nextSecs < endSecs unless first transition ever was >= endSecs. + } // else: we have no data - prevSecs is still endSecs, nextDate is still nil + } + // Either nextDate is nil or nextSecs is at its transition. + + // Wind through remaining transitions (spanning at most a year), one at a time: + while (nextDate != nil && nextSecs < endSecs) { + prevSecs = nextSecs; nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; nextSecs = [nextDate timeIntervalSince1970]; - while (nextDate != nil && nextSecs > prevSecs && nextSecs < endSecs) { - secsList.append(nextSecs); - prevSecs = nextSecs; - nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; - nextSecs = [nextDate timeIntervalSince1970]; - } + if (nextSecs <= prevSecs) // presumably no later data available + break; } - if (secsList.size() >= 1) - return data(qint64(secsList.constLast()) * 1000); - else - return invalidData(); + if (prevSecs < endSecs) // i.e. we did make it into that while loop + return data(qint64(prevSecs * 1e3)); + + // No transition data; or first transition later than requested time. + return invalidData(); } QByteArray QMacTimeZonePrivate::systemTimeZoneId() const From 957c1d9abd854a3b5c43ace807ab7cbf89c91491 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 28 Jul 2017 13:25:41 +0200 Subject: [PATCH 016/146] Use a proper test for absolute path for qmake's location QFileInfo.isRelative() deems any path starting with a slash to be absolute; on MS-Win, such paths need a drive specifier (unless they're UNC), so use IoUtils's more robust test for absolute paths. Change-Id: I7d0872a87833cbf1cc1a6ef107941adc4c529624 Reviewed-by: Oswald Buddenhagen --- qmake/option.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qmake/option.cpp b/qmake/option.cpp index 4da2a1ae2c9..8e457a2626c 100644 --- a/qmake/option.cpp +++ b/qmake/option.cpp @@ -28,6 +28,7 @@ #include "option.h" #include "cachekeys.h" +#include #include #include #include @@ -38,6 +39,8 @@ QT_BEGIN_NAMESPACE +using namespace QMakeInternal; + EvalHandler Option::evalHandler; QMakeGlobals *Option::globals; ProFileCache *Option::proFileCache; @@ -325,7 +328,7 @@ Option::init(int argc, char **argv) #endif if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING) Option::qmake_mode = default_mode(argv0); - if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) { + if (!argv0.isEmpty() && IoUtils::isAbsolutePath(argv0)) { globals->qmake_abslocation = argv0; } else if (argv0.contains(QLatin1Char('/')) #ifdef Q_OS_WIN From 13f6eb9773c0a4c64da7070be4ac3bbf66f8c82d Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 10 Jan 2018 16:29:17 +0100 Subject: [PATCH 017/146] Doc: Mention exact Qt version the third party attributions apply to MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do add, remove or update third party code in minor releases, sometimes even in patch level releases. However, the documentation is supposed to be valid for all existing Qt 5 versions, but doing this for attributions would require infrastructure we don't have. Therefore rather make it explicit which Qt version the attributions apply to. Also mention since when Qt is available under LGPLv3 (starting with Qt 5.4). Task-number: QTBUG-65665 Change-Id: I328b5bf0c143f78ea61aad51f0644c3cbb6dee49 Reviewed-by: Edward Welbourne Reviewed-by: Topi Reiniö --- doc/global/macros.qdocconf | 1 + src/corelib/doc/src/qtcore-index.qdoc | 7 ++++--- src/gui/doc/src/qtgui.qdoc | 5 +++-- src/sql/doc/src/qtsql.qdoc | 5 +++-- src/testlib/doc/src/qttest-index.qdoc | 5 +++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/doc/global/macros.qdocconf b/doc/global/macros.qdocconf index 5544da425a9..dbf8c5cc6a6 100644 --- a/doc/global/macros.qdocconf +++ b/doc/global/macros.qdocconf @@ -18,6 +18,7 @@ macro.QA = "\\e{Qt Assistant}" macro.QD = "\\e{Qt Designer}" macro.QL = "\\e{Qt Linguist}" macro.QQV = "\\e{Qt QML Viewer}" +macro.QtVersion = "$QT_VERSION" macro.param = "\\e" macro.raisedaster.HTML = "*" macro.rarrow.HTML = "→" diff --git a/src/corelib/doc/src/qtcore-index.qdoc b/src/corelib/doc/src/qtcore-index.qdoc index 9004c018ed0..04af0e9416b 100644 --- a/src/corelib/doc/src/qtcore-index.qdoc +++ b/src/corelib/doc/src/qtcore-index.qdoc @@ -104,17 +104,18 @@ \section1 Licenses and Attributions Qt Core is available under commercial licenses from \l{The Qt Company}. - In addition, it is available under the + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are \l{GNU Lesser General Public License, version 3}, or the \l{GNU General Public License, version 2}. See \l{Qt Licensing} for further details. Executables on Windows potentially link against \l{The qtmain Library}. This library is available - under commercial licenses, and in addition under the + under commercial licenses and also under the \l{BSD 3-clause "New" or "Revised" License}. - Furthermore Qt Core potentially contains third party + Furthermore, Qt Core in Qt \QtVersion may contain third party modules under following permissive licenses: \generatelist{groupsbymodule attributions-qtcore} diff --git a/src/gui/doc/src/qtgui.qdoc b/src/gui/doc/src/qtgui.qdoc index a9fe520d5e9..9a486569c9b 100644 --- a/src/gui/doc/src/qtgui.qdoc +++ b/src/gui/doc/src/qtgui.qdoc @@ -190,12 +190,13 @@ \section1 Licenses and Attributions Qt GUI is available under commercial licenses from \l{The Qt Company}. - In addition, it is available under the + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are \l{GNU Lesser General Public License, version 3}, or the \l{GNU General Public License, version 2}. See \l{Qt Licensing} for further details. - Furthermore Qt GUI potentially contains third party + Furthermore, Qt GUI in Qt \QtVersion may contain third-party modules under following permissive licenses: \generatelist{groupsbymodule attributions-qtgui} diff --git a/src/sql/doc/src/qtsql.qdoc b/src/sql/doc/src/qtsql.qdoc index 56d714becf6..f0d74739b01 100644 --- a/src/sql/doc/src/qtsql.qdoc +++ b/src/sql/doc/src/qtsql.qdoc @@ -54,12 +54,13 @@ \section1 Licenses and Attributions Qt SQL is available under commercial licenses from \l{The Qt Company}. - In addition, it is available under the + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are \l{GNU Lesser General Public License, version 3}, or the \l{GNU General Public License, version 2}. See \l{Qt Licensing} for further details. - Furthermore Qt SQL potentially contains third party + Furthermore, Qt SQL in Qt \QtVersion may contain third party modules under following permissive licenses: \generatelist{groupsbymodule attributions-qtsql} diff --git a/src/testlib/doc/src/qttest-index.qdoc b/src/testlib/doc/src/qttest-index.qdoc index 36ebfee463b..f5b077e8e8d 100644 --- a/src/testlib/doc/src/qttest-index.qdoc +++ b/src/testlib/doc/src/qttest-index.qdoc @@ -53,12 +53,13 @@ \section1 Licenses and Attributions Qt Test is available under commercial licenses from \l{The Qt Company}. - In addition, it is available under the + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are \l{GNU Lesser General Public License, version 3}, or the \l{GNU General Public License, version 2}. See \l{Qt Licensing} for further details. - Furthermore Qt Test potentially contains third party + Furthermore, Qt Test in Qt \QtVersion may contain third party modules under following permissive licenses: \generatelist{groupsbymodule attributions-qttestlib} From dc742e9394c2796acce1317af7bb9fc304f820a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tero=20Alam=C3=A4ki?= Date: Thu, 18 Jan 2018 13:16:44 +0200 Subject: [PATCH 018/146] Enable glyph cache workaround for Mali-T880 Change-Id: I531e57c26e886cd8de09ca860d7e10b05d1a724b Reviewed-by: Laszlo Agocs --- src/gui/kernel/qopenglcontext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index ad5e0b518d9..620f7f74c81 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -1002,6 +1002,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface) if (rendererString) needsWorkaround = qstrncmp(rendererString, "Mali-4xx", 6) == 0 // Mali-400, Mali-450 + || qstrcmp(rendererString, "Mali-T880") == 0 || qstrncmp(rendererString, "Adreno (TM) 2xx", 13) == 0 // Adreno 200, 203, 205 || qstrncmp(rendererString, "Adreno 2xx", 8) == 0 // Same as above but without the '(TM)' || qstrncmp(rendererString, "Adreno (TM) 30x", 14) == 0 // Adreno 302, 305 From e211ab76d766878b4dbe88901b9a7a4a70ce7332 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Thu, 18 Jan 2018 18:43:25 +0100 Subject: [PATCH 019/146] Handle OOM condition in the validation of plugin metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A large plugin dll (e.g., one with many MB of debug info) could cause a 32-bit application to crash when the entire dll file could not fit within the address space of the process. The code for validating a plugin library and retrieving metadata from it first tried to map the entire file in memory, which failed for large files, returning NULL. In this case, the code tried then to read the entire file via QFile::readAll(), which deep below caused a bad_alloc exception in malloc, resulting in the termination of the application. This change handles the case where the library could not be mapped into memory, in spite of memory mapping being supported, by reporting the error and returning false, making the plugin unavailable. [ChangeLog][QtCore][QPluginLoader] Fixed a bug that would cause the Qt plugin scanning system to allocate too much memory and possibly crash the process. Task-number: QTBUG-65197 Change-Id: I8c7235d86175c9fcd2b87fcb1151570da9b9ebe3 Reviewed-by: Jan Arve Sæther --- src/corelib/plugin/qlibrary.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index ebad7f1751e..9e6e70756f3 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -237,21 +237,34 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) if (lib) lib->errorString = file.errorString(); if (qt_debug_component()) { - qWarning("%s: %s", (const char*) QFile::encodeName(library), + qWarning("%s: %s", QFile::encodeName(library).constData(), qPrintable(QSystemError::stdString())); } return false; } QByteArray data; - const char *filedata = 0; ulong fdlen = file.size(); - filedata = (char *) file.map(0, fdlen); + const char *filedata = reinterpret_cast(file.map(0, fdlen)); + if (filedata == 0) { - // try reading the data into memory instead - data = file.readAll(); - filedata = data.constData(); - fdlen = data.size(); + if (uchar *mapdata = file.map(0, 1)) { + file.unmap(mapdata); + // Mapping is supported, but failed for the entire file, likely due to OOM. + // Return false, as readAll() would cause a bad_alloc and terminate the process. + if (lib) + lib->errorString = QLibrary::tr("Out of memory while loading plugin '%1'.").arg(library); + if (qt_debug_component()) { + qWarning("%s: %s", QFile::encodeName(library).constData(), + qPrintable(QSystemError::stdString(ENOMEM))); + } + return false; + } else { + // Try reading the data into memory instead. + data = file.readAll(); + filedata = data.constData(); + fdlen = data.size(); + } } /* @@ -745,7 +758,7 @@ void QLibraryPrivate::updatePluginState() if (qt_debug_component()) { qWarning("In %s:\n" " Plugin uses incompatible Qt library (%d.%d.%d) [%s]", - (const char*) QFile::encodeName(fileName), + QFile::encodeName(fileName).constData(), (qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff, debug ? "debug" : "release"); } From 6d50f746fe05a7008b63818e77784dd0c99270a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Ryyn=C3=A4nen?= Date: Fri, 2 Jun 2017 12:53:23 +0300 Subject: [PATCH 020/146] Support for Q_OS_ANDROID_EMBEDDED and android-embedded build flags The Embedded Android build (Boot to Qt Android injection) is defined by having both Q_OS_ANDROID and Q_OS_ANDROID_EMBEDDED flags defined, as well as having Qt config android-embedded. This commit enables the possibility to build embedded Android builds. (i.e. Qt build for Android baselayer only, without JNI) Change-Id: I8406e959fdf1c8d9efebbbe53f1a391fa25f336a Reviewed-by: Oswald Buddenhagen Reviewed-by: Paul Olav Tvete --- .../features/android/android_deployment_settings.prf | 2 +- src/corelib/global/qglobal.cpp | 12 ++++++------ src/corelib/global/qlogging.cpp | 4 ++-- src/corelib/global/qoperatingsystemversion.cpp | 4 ++-- src/corelib/io/io.pri | 2 +- src/corelib/kernel/kernel.pri | 2 +- src/corelib/kernel/qcoreapplication.cpp | 6 +++--- src/corelib/tools/qsimd_p.h | 2 +- src/corelib/tools/qtimezone.cpp | 8 ++++---- src/corelib/tools/qtimezoneprivate_p.h | 6 +++--- src/corelib/tools/tools.pri | 2 +- src/gui/kernel/qguiapplication.cpp | 4 ++-- src/network/ssl/qsslsocket_openssl.cpp | 2 ++ src/network/ssl/qsslsocket_p.h | 2 +- src/network/ssl/ssl.pri | 2 +- .../eglconvenience/qeglplatformcontext.cpp | 4 ++-- src/plugins/bearer/bearer.pro | 2 +- src/plugins/platforms/eglfs/api/qeglfswindow.cpp | 2 +- .../platforms/linuxfb/qlinuxfbintegration.cpp | 6 +++--- src/plugins/platforms/platforms.pro | 2 +- src/src.pro | 8 +++++--- tests/auto/corelib/io/qdatastream/qdatastream.pro | 2 +- tests/auto/corelib/io/qdir/qdir.pro | 2 +- tests/auto/corelib/io/qdir/tst_qdir.cpp | 6 +++--- .../corelib/io/qdiriterator/tst_qdiriterator.cpp | 2 +- tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp | 4 ++-- .../io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp | 2 +- tests/auto/corelib/io/qiodevice/qiodevice.pro | 2 +- tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp | 2 +- tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp | 2 +- .../corelib/io/qloggingregistry/qloggingregistry.pro | 2 +- .../corelib/io/qresourceengine/qresourceengine.pro | 2 +- .../io/qresourceengine/tst_qresourceengine.cpp | 6 +++--- .../corelib/io/qtemporarydir/tst_qtemporarydir.cpp | 2 +- .../corelib/io/qtemporaryfile/qtemporaryfile.pro | 2 +- .../corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp | 8 ++++---- .../auto/corelib/kernel/qtranslator/qtranslator.pro | 2 +- .../corelib/kernel/qtranslator/tst_qtranslator.cpp | 2 +- tests/auto/corelib/tools/qbytearray/qbytearray.pro | 2 +- tests/auto/corelib/tools/qchar/qchar.pro | 2 +- tests/auto/corelib/tools/qcollator/tst_qcollator.cpp | 2 +- .../qcommandlineparser/tst_qcommandlineparser.cpp | 6 +++--- .../tools/qcryptographichash/qcryptographichash.pro | 2 +- .../qtextboundaryfinder/qtextboundaryfinder.pro | 2 +- tests/auto/gui/image/qimage/qimage.pro | 2 +- tests/auto/gui/image/qimagereader/qimagereader.pro | 2 +- tests/auto/gui/image/qimagewriter/qimagewriter.pro | 2 +- tests/auto/gui/painting/qpainter/qpainter.pro | 2 +- .../tst_qprocess_and_guieventloop.cpp | 2 +- tests/auto/widgets/dialogs/qsidebar/tst_qsidebar.cpp | 2 +- .../qgraphicsscene/tst_qgraphicsscene.cpp | 6 +++--- tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro | 2 +- .../widgets/itemviews/qdirmodel/tst_qdirmodel.cpp | 4 ++-- tests/auto/widgets/kernel/qlayout/qlayout.pro | 2 +- tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp | 2 +- tests/auto/widgets/styles/qstyle/qstyle.pro | 2 +- 56 files changed, 92 insertions(+), 88 deletions(-) diff --git a/mkspecs/features/android/android_deployment_settings.prf b/mkspecs/features/android/android_deployment_settings.prf index 913ab71412b..e6b2431f9a2 100644 --- a/mkspecs/features/android/android_deployment_settings.prf +++ b/mkspecs/features/android/android_deployment_settings.prf @@ -1,4 +1,4 @@ -contains(TEMPLATE, ".*app"):!build_pass: { +contains(TEMPLATE, ".*app"):!build_pass:!android-embedded { defineReplace(emitString) { return("\"$$replace(1, \\\\, \\\\)\"") diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index d609f6a30a0..ea2c8d3ae2c 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -81,7 +81,7 @@ # include #endif -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) #include #endif @@ -2312,7 +2312,7 @@ static bool findUnixOsVersion(QUnixOSVersion &v) # endif // USE_ETC_OS_RELEASE #endif // Q_OS_UNIX -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) static const char *osVer_helper(QOperatingSystemVersion) { /* Data: @@ -2793,7 +2793,7 @@ QString QSysInfo::productVersion() */ QString QSysInfo::prettyProductName() { -#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN) +#if (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN) const auto version = QOperatingSystemVersion::current(); const char *name = osVer_helper(version); if (name) @@ -3349,7 +3349,7 @@ bool qunsetenv(const char *varName) #endif } -#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) && (__ANDROID_API__ < 21) typedef QThreadStorage AndroidRandomStorage; Q_GLOBAL_STATIC(AndroidRandomStorage, randomTLS) @@ -3383,7 +3383,7 @@ Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value */ void qsrand(uint seed) { -#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) && (__ANDROID_API__ < 21) if (randomTLS->hasLocalData()) { randomTLS->localData().callMethod("setSeed", "(J)V", jlong(seed)); return; @@ -3437,7 +3437,7 @@ void qsrand(uint seed) */ int qrand() { -#if defined(Q_OS_ANDROID) && (__ANDROID_API__ < 21) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) && (__ANDROID_API__ < 21) AndroidRandomStorage *randomStorage = randomTLS(); if (!randomStorage) return rand(); diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 1307118bdf3..f99675a7b96 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1546,7 +1546,7 @@ static void syslog_default_message_handler(QtMsgType type, const char *message) } #endif -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) static void android_default_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message) @@ -1594,7 +1594,7 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con #elif QT_CONFIG(syslog) syslog_default_message_handler(type, logMessage.toUtf8().constData()); return; -#elif defined(Q_OS_ANDROID) +#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) android_default_message_handler(type, context, logMessage); return; #endif diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp index 594dc6bc17c..3210a0a1255 100644 --- a/src/corelib/global/qoperatingsystemversion.cpp +++ b/src/corelib/global/qoperatingsystemversion.cpp @@ -44,7 +44,7 @@ #include -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) #include #endif @@ -160,7 +160,7 @@ QOperatingSystemVersion QOperatingSystemVersion::current() { QOperatingSystemVersion version; version.m_os = currentType(); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) #ifndef QT_BOOTSTRAPPED const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField( "android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString()); diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index d24c2905083..b2c531a8ad6 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -167,7 +167,7 @@ win32 { } else { LIBS += -framework MobileCoreServices } - } else:android { + } else:android:!android-embedded { SOURCES += \ io/qstandardpaths_android.cpp \ io/qstorageinfo_unix.cpp diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 9bc6e198f83..66f1294d53e 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -199,7 +199,7 @@ qnx:qtConfig(qqnx_pps) { kernel/qppsobjectprivate_p.h } -android { +android:!android-embedded { SOURCES += \ kernel/qjnionload.cpp \ kernel/qjnihelpers.cpp \ diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index ee269ef8de9..12c2669f360 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -95,7 +95,7 @@ #endif #endif // QT_NO_QOBJECT -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) # include # include #endif @@ -180,7 +180,7 @@ QString QCoreApplicationPrivate::appVersion() const #ifndef QT_BOOTSTRAPPED # ifdef Q_OS_DARWIN applicationVersion = infoDictionaryStringProperty(QStringLiteral("CFBundleVersion")); -# elif defined(Q_OS_ANDROID) +# elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QJNIObjectPrivate context(QtAndroidPrivate::context()); if (context.isValid()) { QJNIObjectPrivate pm = context.callObjectMethod( @@ -2189,7 +2189,7 @@ QString QCoreApplication::applicationFilePath() } #endif #if defined( Q_OS_UNIX ) -# if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) +# if defined(Q_OS_LINUX) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_EMBEDDED)) // Try looking for a /proc//exe symlink first which points to // the absolute path of the executable QFileInfo pfi(QString::fromLatin1("/proc/%1/exe").arg(getpid())); diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index 05f118a9eb5..36c0a9097b2 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -198,7 +198,7 @@ // SSE intrinsics #if defined(__SSE2__) || (defined(QT_COMPILER_SUPPORTS_SSE2) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -#if defined(QT_LINUXBASE) +#if defined(QT_LINUXBASE) || defined(Q_OS_ANDROID_EMBEDDED) /// this is an evil hack - the posix_memalign declaration in LSB /// is wrong - see http://bugs.linuxbase.org/show_bug.cgi?id=2431 # define posix_memalign _lsb_hack_posix_memalign diff --git a/src/corelib/tools/qtimezone.cpp b/src/corelib/tools/qtimezone.cpp index c4cd76c59c6..567c819813d 100644 --- a/src/corelib/tools/qtimezone.cpp +++ b/src/corelib/tools/qtimezone.cpp @@ -62,9 +62,9 @@ static QTimeZonePrivate *newBackendTimeZone() #else #if defined Q_OS_MAC return new QMacTimeZonePrivate(); -#elif defined Q_OS_ANDROID +#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) return new QAndroidTimeZonePrivate(); -#elif defined Q_OS_UNIX +#elif defined(Q_OS_UNIX) || defined(Q_OS_ANDROID_EMBEDDED) return new QTzTimeZonePrivate(); // Registry based timezone backend not available on WinRT #elif defined Q_OS_WIN @@ -89,9 +89,9 @@ static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId) #else #if defined Q_OS_MAC return new QMacTimeZonePrivate(ianaId); -#elif defined Q_OS_ANDROID +#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) return new QAndroidTimeZonePrivate(ianaId); -#elif defined Q_OS_UNIX +#elif defined(Q_OS_UNIX) || defined(Q_OS_ANDROID_EMBEDDED) return new QTzTimeZonePrivate(ianaId); // Registry based timezone backend not available on WinRT #elif defined Q_OS_WIN diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h index 74b79dce162..83e06ffcb08 100644 --- a/src/corelib/tools/qtimezoneprivate_p.h +++ b/src/corelib/tools/qtimezoneprivate_p.h @@ -68,7 +68,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone); #include #endif // Q_OS_WIN -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) #include #endif @@ -266,7 +266,7 @@ private: }; #endif -#if defined Q_OS_UNIX && !defined Q_OS_MAC && !defined Q_OS_ANDROID +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_EMBEDDED)) struct QTzTransitionTime { qint64 atMSecsSinceEpoch; @@ -443,7 +443,7 @@ private: }; #endif // Q_OS_WIN -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) class QAndroidTimeZonePrivate Q_DECL_FINAL : public QTimeZonePrivate { public: diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 7ba3ff4a8bd..bea8e974352 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -158,7 +158,7 @@ qtConfig(timezone) { tools/qtimezoneprivate.cpp !nacl:darwin: \ SOURCES += tools/qtimezoneprivate_mac.mm - else: android: \ + else: android:!android-embedded: \ SOURCES += tools/qtimezoneprivate_android.cpp else: unix: \ SOURCES += tools/qtimezoneprivate_tz.cpp diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index cff11367f7e..25818b456a1 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2040,7 +2040,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE QWindow *window = e->window.data(); modifier_buttons = e->modifiers; if (e->nullWindow() -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) || e->key == Qt::Key_Back || e->key == Qt::Key_Menu #endif ) { @@ -2076,7 +2076,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE if (window && !window->d_func()->blockedByModalWindow) QGuiApplication::sendSpontaneousEvent(window, &ev); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) else ev.setAccepted(false); diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index ab82cdcfc9a..f5b493897ea 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -727,12 +727,14 @@ QList QSslSocketPrivate::systemCaCertificates() directories << ministroPath; nameFilters << QLatin1String("*.der"); platformEncodingFormat = QSsl::Der; +# ifndef Q_OS_ANDROID_EMBEDDED if (ministroPath.isEmpty()) { QList certificateData = fetchSslCertificateData(); for (int i = 0; i < certificateData.size(); ++i) { systemCerts.append(QSslCertificate::fromData(certificateData.at(i), QSsl::Der)); } } else +# endif //Q_OS_ANDROID_EMBEDDED # endif //Q_OS_ANDROID { currentDir.setNameFilters(nameFilters); diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 827f27cff11..217d6be1dc4 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -209,7 +209,7 @@ public: private: static bool ensureLibraryLoaded(); static void ensureCiphersAndCertsLoaded(); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) static QList fetchSslCertificateData(); #endif diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri index 52ce2eeade5..d2b0c2d60d3 100644 --- a/src/network/ssl/ssl.pri +++ b/src/network/ssl/ssl.pri @@ -70,7 +70,7 @@ qtConfig(ssl) { darwin:SOURCES += ssl/qsslsocket_mac_shared.cpp - android: SOURCES += ssl/qsslsocket_openssl_android.cpp + android:!android-embedded: SOURCES += ssl/qsslsocket_openssl_android.cpp # Add optional SSL libs # Static linking of OpenSSL with msvc: diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 674ab290124..7a9a98573ed 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -45,7 +45,7 @@ #include #include -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) #include #endif #ifndef Q_OS_WIN @@ -332,7 +332,7 @@ void QEGLPlatformContext::updateFormatFromGL() QByteArray version = QByteArray(reinterpret_cast(s)); int major, minor; if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) // Some Android 4.2.2 devices report OpenGL ES 3.0 without the functions being available. static int apiLevel = QtAndroidPrivate::androidSdkVersion(); if (apiLevel <= 17 && major >= 3) { diff --git a/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro index 824fd0388f9..afdc6131672 100644 --- a/src/plugins/bearer/bearer.pro +++ b/src/plugins/bearer/bearer.pro @@ -6,6 +6,6 @@ QT_FOR_CONFIG += network-private SUBDIRS += connman networkmanager } -android:SUBDIRS += android +android:!android-embedded: SUBDIRS += android isEmpty(SUBDIRS):SUBDIRS = generic diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp index 9b4732eab4c..17e4aa1df8a 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp @@ -117,7 +117,7 @@ void QEglFSWindow::create() QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); if (screen->primarySurface() != EGL_NO_SURFACE) { if (Q_UNLIKELY(!isRaster() || !compositor->targetWindow())) { -#if !defined(Q_OS_ANDROID) +#if !defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_EMBEDDED) // We can have either a single OpenGL window or multiple raster windows. // Other combinations cannot work. qFatal("EGLFS: OpenGL windows cannot be mixed with others."); diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index 6f79cd96d30..f835dbf6d41 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -59,13 +59,13 @@ #include #endif -#if QT_CONFIG(evdev) && !defined(Q_OS_ANDROID) +#if QT_CONFIG(evdev) #include #include #include #endif -#if QT_CONFIG(tslib) && !defined(Q_OS_ANDROID) +#if QT_CONFIG(tslib) #include #endif @@ -162,7 +162,7 @@ void QLinuxFbIntegration::createInputHandlers() new QTsLibMouseHandler(QLatin1String("TsLib"), QString()); #endif -#if QT_CONFIG(evdev) && !defined(Q_OS_ANDROID) +#if QT_CONFIG(evdev) new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString(), this); new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString(), this); #if QT_CONFIG(tslib) diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 9ccc2b54b9c..9414f01ef0f 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -1,7 +1,7 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private -android: SUBDIRS += android +android:!android-embedded: SUBDIRS += android !android: SUBDIRS += minimal diff --git a/src/src.pro b/src/src.pro index 43fc06f2e5f..3e32f7edb05 100644 --- a/src/src.pro +++ b/src/src.pro @@ -193,9 +193,11 @@ qtConfig(gui) { src_plugins.depends += src_gui src_platformsupport src_platformheaders src_testlib.depends += src_gui # if QtGui is enabled, QtTest requires QtGui's headers qtConfig(widgets) { - SUBDIRS += src_tools_uic src_widgets src_printsupport + SUBDIRS += src_tools_uic src_widgets + !android-embedded: SUBDIRS += src_printsupport TOOLS += src_tools_uic - src_plugins.depends += src_widgets src_printsupport + src_plugins.depends += src_widgets + !android-embedded: src_plugins.depends += src_printsupport src_testlib.depends += src_widgets # if QtWidgets is enabled, QtTest requires QtWidgets's headers qtConfig(opengl) { SUBDIRS += src_opengl @@ -207,7 +209,7 @@ SUBDIRS += src_plugins nacl: SUBDIRS -= src_network src_testlib -android: SUBDIRS += src_android src_3rdparty_gradle +android:!android-embedded: SUBDIRS += src_android src_3rdparty_gradle TR_EXCLUDE = \ src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_uic src_tools_qlalr \ diff --git a/tests/auto/corelib/io/qdatastream/qdatastream.pro b/tests/auto/corelib/io/qdatastream/qdatastream.pro index 291b3eb6110..25f8b889a0a 100644 --- a/tests/auto/corelib/io/qdatastream/qdatastream.pro +++ b/tests/auto/corelib/io/qdatastream/qdatastream.pro @@ -5,7 +5,7 @@ SOURCES = tst_qdatastream.cpp TESTDATA += datastream.q42 -android { +android:!android-embedded { RESOURCES += \ testdata.qrc } diff --git a/tests/auto/corelib/io/qdir/qdir.pro b/tests/auto/corelib/io/qdir/qdir.pro index 48709223122..2252e71cd8a 100644 --- a/tests/auto/corelib/io/qdir/qdir.pro +++ b/tests/auto/corelib/io/qdir/qdir.pro @@ -8,6 +8,6 @@ TESTDATA += testdir testData searchdir resources entrylist types tst_qdir.cpp contains(CONFIG, builtin_testdata): DEFINES += BUILTIN_TESTDATA -android { +android:!android-embedded { RESOURCES += android_testdata.qrc } diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index 8dbac281831..9d47bb28845 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -228,13 +228,13 @@ private: Q_DECLARE_METATYPE(tst_QDir::UncHandling) tst_QDir::tst_QDir() -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) : m_dataPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) #elif !defined(BUILTIN_TESTDATA) : m_dataPath(QFileInfo(QFINDTESTDATA("testData")).absolutePath()) #endif { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString resourceSourcePath = QStringLiteral(":/android_testdata/"); QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories); while (it.hasNext()) { @@ -2186,7 +2186,7 @@ void tst_QDir::equalityOperator_data() QString pathinroot(QDir::rootPath() + QLatin1String("assets/..")); #elif defined (Q_OS_WIN) QString pathinroot("c:/windows/.."); -#elif defined(Q_OS_ANDROID) +#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString pathinroot("/system/.."); #elif defined(Q_OS_HAIKU) QString pathinroot("/boot/.."); diff --git a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp index 6450e9af7b3..a55989aacd3 100644 --- a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp +++ b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp @@ -118,7 +118,7 @@ private: void tst_QDirIterator::initTestCase() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString testdata_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); QString resourceSourcePath = QStringLiteral(":/"); QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories); diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp index efb261ce7ea..38db4c7b631 100644 --- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -1200,7 +1200,7 @@ void tst_QFileInfo::fileTimes() QEXPECT_FAIL("", "WinRT does not allow timestamp handling change in the filesystem due to sandboxing", Continue); #elif defined(Q_OS_QNX) QEXPECT_FAIL("", "QNX uses the noatime filesystem option", Continue); -#elif defined(Q_OS_ANDROID) +#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) if (fileInfo.lastRead() <= beforeRead) QEXPECT_FAIL("", "Android may use relatime or noatime on mounts", Continue); #endif @@ -1664,7 +1664,7 @@ void tst_QFileInfo::isWritable() void tst_QFileInfo::isExecutable() { QString appPath = QCoreApplication::applicationDirPath(); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) appPath += "/libtst_qfileinfo.so"; #else appPath += "/tst_qfileinfo"; diff --git a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp index 154c7ec5bfa..b05a876a52f 100644 --- a/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp +++ b/tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp @@ -89,7 +89,7 @@ tst_QFileSystemWatcher::tst_QFileSystemWatcher() m_tempDirPattern += QStringLiteral("tst_qfilesystemwatcherXXXXXX"); #endif // QT_NO_FILESYSTEMWATCHER -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QDir::setCurrent(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); #endif } diff --git a/tests/auto/corelib/io/qiodevice/qiodevice.pro b/tests/auto/corelib/io/qiodevice/qiodevice.pro index 945022a289c..1c978953d67 100644 --- a/tests/auto/corelib/io/qiodevice/qiodevice.pro +++ b/tests/auto/corelib/io/qiodevice/qiodevice.pro @@ -6,7 +6,7 @@ SOURCES = tst_qiodevice.cpp TESTDATA += tst_qiodevice.cpp MOC_DIR=tmp -android { +android:!android-embedded { RESOURCES += \ android_testdata.qrc } diff --git a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp index a76fd4703e3..9e0b9c23292 100644 --- a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp +++ b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp @@ -66,7 +66,7 @@ private: void tst_QIODevice::initTestCase() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QVERIFY(QFileInfo(QStringLiteral("./tst_qiodevice.cpp")).exists() || QFile::copy(QStringLiteral(":/tst_qiodevice.cpp"), QStringLiteral("./tst_qiodevice.cpp"))); #endif diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp index d2f345feb5e..59196dc40b1 100644 --- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp +++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp @@ -72,7 +72,7 @@ public: void tst_QLockFile::initTestCase() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("This test requires deploying and running external console applications"); #elif !QT_CONFIG(process) QSKIP("This test requires QProcess support"); diff --git a/tests/auto/corelib/io/qloggingregistry/qloggingregistry.pro b/tests/auto/corelib/io/qloggingregistry/qloggingregistry.pro index 287ab309936..ac976e9b9cc 100644 --- a/tests/auto/corelib/io/qloggingregistry/qloggingregistry.pro +++ b/tests/auto/corelib/io/qloggingregistry/qloggingregistry.pro @@ -7,7 +7,7 @@ QT = core core-private testlib SOURCES += tst_qloggingregistry.cpp TESTDATA += qtlogging.ini -android { +android:!android-embedded { RESOURCES += \ android_testdata.qrc } diff --git a/tests/auto/corelib/io/qresourceengine/qresourceengine.pro b/tests/auto/corelib/io/qresourceengine/qresourceengine.pro index 658201e03a7..f937d23fe2c 100644 --- a/tests/auto/corelib/io/qresourceengine/qresourceengine.pro +++ b/tests/auto/corelib/io/qresourceengine/qresourceengine.pro @@ -18,6 +18,6 @@ TESTDATA += \ testqrc/* GENERATED_TESTDATA = $${runtime_resource.target} -android { +android:!android-embedded { RESOURCES += android_testdata.qrc } diff --git a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp index 7fdd00876f1..ab1866fb2da 100644 --- a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp +++ b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp @@ -36,7 +36,7 @@ class tst_QResourceEngine: public QObject public: tst_QResourceEngine() -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) : m_runtimeResourceRcc(QFileInfo(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QStringLiteral("/runtime_resource.rcc")).absoluteFilePath()) #else : m_runtimeResourceRcc(QFINDTESTDATA("runtime_resource.rcc")) @@ -64,7 +64,7 @@ private: void tst_QResourceEngine::initTestCase() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString sourcePath(QStringLiteral(":/android_testdata/")); QString dataPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); @@ -121,7 +121,7 @@ void tst_QResourceEngine::checkStructure_data() << QLatin1String("test") << QLatin1String("withoutslashes"); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) rootContents.insert(1, QLatin1String("android_testdata")); #endif diff --git a/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp index 4cb3bfe5490..21936faca5d 100644 --- a/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp +++ b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp @@ -288,7 +288,7 @@ void tst_QTemporaryDir::nonWritableCurrentDir() { #ifdef Q_OS_UNIX -# if defined(Q_OS_ANDROID) +# if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) const char nonWritableDir[] = "/data"; # else const char nonWritableDir[] = "/home"; diff --git a/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro b/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro index e17cb05cd8b..11a5d58dc8f 100644 --- a/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro +++ b/tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro @@ -5,6 +5,6 @@ SOURCES = tst_qtemporaryfile.cpp TESTDATA += tst_qtemporaryfile.cpp RESOURCES += qtemporaryfile.qrc -android { +android:!android-embedded { RESOURCES += android_testdata.qrc } diff --git a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp index 64b61839c12..a4e7aa03166 100644 --- a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp @@ -99,7 +99,7 @@ void tst_QTemporaryFile::initTestCase() QVERIFY(QDir("test-XXXXXX").exists() || QDir().mkdir("test-XXXXXX")); QCoreApplication::setApplicationName("tst_qtemporaryfile"); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString sourceDir(":/android_testdata/"); QDirIterator it(sourceDir, QDirIterator::Subdirectories); while (it.hasNext()) { @@ -323,7 +323,7 @@ void tst_QTemporaryFile::nonWritableCurrentDir() ChdirOnReturn cor(QDir::currentPath()); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QDir::setCurrent("/data"); #else QDir::setCurrent("/home"); @@ -492,7 +492,7 @@ void tst_QTemporaryFile::renameFdLeak() { #ifdef Q_OS_UNIX -# if defined(Q_OS_ANDROID) +# if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) ChdirOnReturn cor(QDir::currentPath()); QDir::setCurrent(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); # endif @@ -701,7 +701,7 @@ void tst_QTemporaryFile::createNativeFile_data() QTest::addColumn("valid"); QTest::addColumn("content"); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) const QString nativeFilePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QStringLiteral("/resources/test.txt"); #else const QString nativeFilePath = QFINDTESTDATA("resources/test.txt"); diff --git a/tests/auto/corelib/kernel/qtranslator/qtranslator.pro b/tests/auto/corelib/kernel/qtranslator/qtranslator.pro index e6732789208..d8924c2d5f2 100644 --- a/tests/auto/corelib/kernel/qtranslator/qtranslator.pro +++ b/tests/auto/corelib/kernel/qtranslator/qtranslator.pro @@ -4,6 +4,6 @@ QT = core testlib SOURCES = tst_qtranslator.cpp RESOURCES += qtranslator.qrc -android: RESOURCES += android_testdata.qrc +android:!android-embedded: RESOURCES += android_testdata.qrc else: TESTDATA += dependencies_la.qm hellotr_la.qm msgfmt_from_po.qm diff --git a/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp b/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp index 66971af7b4d..e3eee6dbdda 100644 --- a/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp +++ b/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp @@ -64,7 +64,7 @@ tst_QTranslator::tst_QTranslator() void tst_QTranslator::initTestCase() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString sourceDir(":/android_testdata/"); QDirIterator it(sourceDir, QDirIterator::Subdirectories); while (it.hasNext()) { diff --git a/tests/auto/corelib/tools/qbytearray/qbytearray.pro b/tests/auto/corelib/tools/qbytearray/qbytearray.pro index f59cdf3524c..c2101b06119 100644 --- a/tests/auto/corelib/tools/qbytearray/qbytearray.pro +++ b/tests/auto/corelib/tools/qbytearray/qbytearray.pro @@ -10,7 +10,7 @@ mac { LIBS += -framework Foundation } -android { +android:!android-embedded { RESOURCES += \ android_testdata.qrc } diff --git a/tests/auto/corelib/tools/qchar/qchar.pro b/tests/auto/corelib/tools/qchar/qchar.pro index 012e591298c..70c12229887 100644 --- a/tests/auto/corelib/tools/qchar/qchar.pro +++ b/tests/auto/corelib/tools/qchar/qchar.pro @@ -5,7 +5,7 @@ SOURCES = tst_qchar.cpp TESTDATA += data/NormalizationTest.txt -android { +android:!android-embedded { RESOURCES += \ testdata.qrc } diff --git a/tests/auto/corelib/tools/qcollator/tst_qcollator.cpp b/tests/auto/corelib/tools/qcollator/tst_qcollator.cpp index 35a9af05f60..480e723f441 100644 --- a/tests/auto/corelib/tools/qcollator/tst_qcollator.cpp +++ b/tests/auto/corelib/tools/qcollator/tst_qcollator.cpp @@ -187,7 +187,7 @@ void tst_QCollator::compare() QCollator collator(locale); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) if (collator.locale() != QLocale()) QSKIP("Posix implementation of collation only supports default locale"); #endif diff --git a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp index 10398f1a99e..527e07593c0 100644 --- a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp +++ b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp @@ -512,7 +512,7 @@ void tst_QCommandLineParser::testVersionOption() #if !QT_CONFIG(process) QSKIP("This test requires QProcess support"); #else -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("Deploying executable applications to file system on Android not supported."); #endif @@ -578,7 +578,7 @@ void tst_QCommandLineParser::testHelpOption() #if !QT_CONFIG(process) QSKIP("This test requires QProcess support"); #else -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("Deploying executable applications to file system on Android not supported."); #endif @@ -625,7 +625,7 @@ void tst_QCommandLineParser::testQuoteEscaping() { #if !QT_CONFIG(process) QSKIP("This test requires QProcess support"); -#elif defined(Q_OS_ANDROID) +#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("Deploying executable applications to file system on Android not supported."); #else QCoreApplication app(empty_argc, empty_argv); diff --git a/tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro b/tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro index 7fead5938be..8d3957a5249 100644 --- a/tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro +++ b/tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro @@ -5,7 +5,7 @@ SOURCES = tst_qcryptographichash.cpp TESTDATA += data/* -android { +android:!android-embedded { RESOURCES += \ testdata.qrc } diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro b/tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro index 8e0216b1759..3c9f03842d1 100644 --- a/tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro +++ b/tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro @@ -5,7 +5,7 @@ SOURCES = tst_qtextboundaryfinder.cpp TESTDATA += data -android { +android:!android-embedded { RESOURCES += \ testdata.qrc } diff --git a/tests/auto/gui/image/qimage/qimage.pro b/tests/auto/gui/image/qimage/qimage.pro index 39ce4e26cb0..56618e0bfad 100644 --- a/tests/auto/gui/image/qimage/qimage.pro +++ b/tests/auto/gui/image/qimage/qimage.pro @@ -5,6 +5,6 @@ SOURCES += tst_qimage.cpp QT += core-private gui-private testlib qtConfig(c++11): CONFIG += c++11 -android: RESOURCES+=qimage.qrc +android:!android-embedded: RESOURCES += qimage.qrc TESTDATA += images/* diff --git a/tests/auto/gui/image/qimagereader/qimagereader.pro b/tests/auto/gui/image/qimagereader/qimagereader.pro index 3d35bf59da7..b06f56dddf8 100644 --- a/tests/auto/gui/image/qimagereader/qimagereader.pro +++ b/tests/auto/gui/image/qimagereader/qimagereader.pro @@ -5,7 +5,7 @@ MOC_DIR=tmp QT += core-private gui-private network testlib RESOURCES += qimagereader.qrc -android { +android:!android-embedded { RESOURCES += android_testdata.qrc } diff --git a/tests/auto/gui/image/qimagewriter/qimagewriter.pro b/tests/auto/gui/image/qimagewriter/qimagewriter.pro index 34adedd1874..e63e57886ce 100644 --- a/tests/auto/gui/image/qimagewriter/qimagewriter.pro +++ b/tests/auto/gui/image/qimagewriter/qimagewriter.pro @@ -3,5 +3,5 @@ TARGET = tst_qimagewriter QT += testlib SOURCES += tst_qimagewriter.cpp MOC_DIR=tmp -android: RESOURCES+= qimagewriter.qrc +android:!android-embedded: RESOURCES += qimagewriter.qrc TESTDATA += images/* diff --git a/tests/auto/gui/painting/qpainter/qpainter.pro b/tests/auto/gui/painting/qpainter/qpainter.pro index 0d3899ee92e..9ccf8f20bad 100644 --- a/tests/auto/gui/painting/qpainter/qpainter.pro +++ b/tests/auto/gui/painting/qpainter/qpainter.pro @@ -9,7 +9,7 @@ SOURCES += tst_qpainter.cpp TESTDATA += drawEllipse/* drawLine_rop_bitmap/* drawPixmap_rop/* drawPixmap_rop_bitmap/* \ task217400.png -android { +android:!android-embedded { RESOURCES += \ testdata.qrc } diff --git a/tests/auto/other/qprocess_and_guieventloop/tst_qprocess_and_guieventloop.cpp b/tests/auto/other/qprocess_and_guieventloop/tst_qprocess_and_guieventloop.cpp index 5842d58fab2..b8d19c0c0d0 100644 --- a/tests/auto/other/qprocess_and_guieventloop/tst_qprocess_and_guieventloop.cpp +++ b/tests/auto/other/qprocess_and_guieventloop/tst_qprocess_and_guieventloop.cpp @@ -40,7 +40,7 @@ private slots: void tst_QProcess_and_GuiEventLoop::waitForAndEventLoop() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("Not supported on Android"); #else diff --git a/tests/auto/widgets/dialogs/qsidebar/tst_qsidebar.cpp b/tests/auto/widgets/dialogs/qsidebar/tst_qsidebar.cpp index 78d0372ac02..3c189f92ccd 100644 --- a/tests/auto/widgets/dialogs/qsidebar/tst_qsidebar.cpp +++ b/tests/auto/widgets/dialogs/qsidebar/tst_qsidebar.cpp @@ -84,7 +84,7 @@ void tst_QSidebar::addUrls() QAbstractItemModel *model = qsidebar.model(); QDir testDir = QDir::home(); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) // temp and home is the same directory on Android testDir.mkdir(QStringLiteral("test")); QVERIFY(testDir.cd(QStringLiteral("test"))); diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp index 7615c5e8216..2a77321bf88 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp @@ -2657,7 +2657,7 @@ void tst_QGraphicsScene::render() void tst_QGraphicsScene::renderItemsWithNegativeWidthOrHeight() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("Test only works on platforms with resizable windows"); #endif @@ -2736,7 +2736,7 @@ protected: void tst_QGraphicsScene::contextMenuEvent_ItemIgnoresTransformations() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("Test fails on some Android devices (QTBUG-44430)"); #endif @@ -4009,7 +4009,7 @@ void tst_QGraphicsScene::polishItems2() void tst_QGraphicsScene::isActive() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("Fails on Android (QTBUG-44430)"); #endif diff --git a/tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro b/tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro index 3527b424c1c..0429315d951 100644 --- a/tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro +++ b/tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro @@ -12,7 +12,7 @@ android { DEFINES += SRCDIR=\\\"$$PWD/\\\" } -android { +android:!android-embedded { RESOURCES += \ testdata.qrc } diff --git a/tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp b/tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp index 2044704e76f..48d39bbb11f 100644 --- a/tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp +++ b/tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp @@ -112,7 +112,7 @@ void tst_QDirModel::getSetCheck() void tst_QDirModel::initTestCase() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString dataPath = SRCDIR; QString resourceSourcePath = QStringLiteral(":/android_testdata"); QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories); @@ -614,7 +614,7 @@ void tst_QDirModel::task196768_sorting() view.setSortingEnabled(true); index2 = model.index(path); -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QEXPECT_FAIL("", "QTBUG-43818", Continue); #else if (EmulationDetector::isRunningArmOnX86()) diff --git a/tests/auto/widgets/kernel/qlayout/qlayout.pro b/tests/auto/widgets/kernel/qlayout/qlayout.pro index 8e0ea1bfdba..e768e19a268 100644 --- a/tests/auto/widgets/kernel/qlayout/qlayout.pro +++ b/tests/auto/widgets/kernel/qlayout/qlayout.pro @@ -6,7 +6,7 @@ QT += widgets widgets-private testlib testlib-private SOURCES += tst_qlayout.cpp TESTDATA += baseline/* -android { +android:!android-embedded { RESOURCES += \ testdata.qrc } diff --git a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp index a55693bb6ce..300a8878bac 100644 --- a/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp +++ b/tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp @@ -337,7 +337,7 @@ void tst_QLayout::adjustSizeShouldMakeSureLayoutIsActivated() void tst_QLayout::testRetainSizeWhenHidden() { -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QSKIP("Test does not work on platforms which default to showMaximized()"); #endif diff --git a/tests/auto/widgets/styles/qstyle/qstyle.pro b/tests/auto/widgets/styles/qstyle/qstyle.pro index 0fb74999463..9ad09402451 100644 --- a/tests/auto/widgets/styles/qstyle/qstyle.pro +++ b/tests/auto/widgets/styles/qstyle/qstyle.pro @@ -3,7 +3,7 @@ TARGET = tst_qstyle QT += widgets testlib testlib-private SOURCES += tst_qstyle.cpp -android { +android:!android-embedded { RESOURCES += \ testdata.qrc } From d80b0eb12c477592b590b768e21dc26c137beadc Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 9 Jan 2018 10:24:18 -0800 Subject: [PATCH 021/146] Doc: make a note about use of QStringLiteral with non-ASCII chars Both ICC and MSVC have bugs concatenating strings and that's despite the standard giving an example ([lex.string] table 9) that says that u"a" "b" is the same as u"ab" We can't change to preprocessor concatenation (u ## STR) because that fails when QStringLiteral is used with a macro instead of an actual string literal. Task-number: QTBUG-65479 Change-Id: I39332e0a867442d58082fffd1504a0a868c291ef Reviewed-by: Friedemann Kleint Reviewed-by: Thiago Macieira --- src/corelib/tools/qstring.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index c0a03e0011e..aff384a2577 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -10802,7 +10802,7 @@ QString QString::toHtmlEscaped() const This cost can be avoided by using QStringLiteral instead: \code - if (node.hasAttribute(QStringLiteral("http-contents-length"))) //... + if (node.hasAttribute(QStringLiteral(u"http-contents-length"))) //... \endcode In this case, QString's internal data will be generated at compile time; no @@ -10822,6 +10822,10 @@ QString QString::toHtmlEscaped() const if (attribute.name() == QLatin1String("http-contents-length")) //... \endcode + \note Some compilers have bugs encoding strings containing characters outside + the US-ASCII character set. Make sure you prefix your string with \c{u} in + those cases. It is optional otherwise. + \sa QByteArrayLiteral */ From 6c3f864ec00c4e20a05f60032048e9fe2c7e116c Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 15 Jan 2018 08:59:09 +0100 Subject: [PATCH 022/146] examples: Fix notepad example for configurations without printsupport Task-number: QTBUG-65735 Change-Id: I7e0d19de4ac92603f2fd033007343f20a408618a Reviewed-by: Nico Vertriest --- examples/widgets/tutorials/notepad/notepad.cpp | 11 +++++++++++ examples/widgets/tutorials/notepad/notepad.pro | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/widgets/tutorials/notepad/notepad.cpp b/examples/widgets/tutorials/notepad/notepad.cpp index b4f6cf7f8f7..44d8597cb7d 100644 --- a/examples/widgets/tutorials/notepad/notepad.cpp +++ b/examples/widgets/tutorials/notepad/notepad.cpp @@ -52,8 +52,15 @@ #include #include #include +#if defined(QT_PRINTSUPPORT_LIB) +#include +#if QT_CONFIG(printer) +#if QT_CONFIG(printdialog) #include +#endif // QT_CONFIG(printdialog) #include +#endif // QT_CONFIG(printer) +#endif // QT_PRINTSUPPORT_LIB #include #include @@ -136,11 +143,15 @@ void Notepad::on_actionSave_as_triggered() void Notepad::on_actionPrint_triggered() { +#if QT_CONFIG(printer) QPrinter printDev; +#if QT_CONFIG(printdialog) QPrintDialog dialog(&printDev, this); if (dialog.exec() == QDialog::Rejected) return; +#endif // QT_CONFIG(printdialog) ui->textEdit->print(&printDev); +#endif // QT_CONFIG(printer) } void Notepad::on_actionExit_triggered() diff --git a/examples/widgets/tutorials/notepad/notepad.pro b/examples/widgets/tutorials/notepad/notepad.pro index a552dacf002..6451f22735e 100644 --- a/examples/widgets/tutorials/notepad/notepad.pro +++ b/examples/widgets/tutorials/notepad/notepad.pro @@ -1,7 +1,7 @@ TEMPLATE = app TARGET = notepad -QT += printsupport +qtHaveModule(printsupport): QT += printsupport requires(qtConfig(fontdialog)) SOURCES += \ From c561c3b8b473d1b0f3557f8d8d89a7c37f847d5d Mon Sep 17 00:00:00 2001 From: Jeremy LUGAGNE Date: Mon, 22 Jan 2018 14:44:35 +0100 Subject: [PATCH 023/146] Fix -developer-build due to missing Q_DECL_OVERRIDE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ie7a2ff0e42131afef1bdec853d09c3b447f9748c Reviewed-by: Sérgio Martins --- src/plugins/platforms/offscreen/qoffscreenintegration.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h index f72587d11ab..154a420e3db 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.h +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h @@ -69,8 +69,8 @@ public: QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; - QStringList themeNames() const; - QPlatformTheme *createPlatformTheme(const QString &name) const; + QStringList themeNames() const Q_DECL_OVERRIDE; + QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE; static QOffscreenIntegration *createOffscreenIntegration(); From 41cdfbe3a473a4f691c193a58206d860cb9c676d Mon Sep 17 00:00:00 2001 From: Alexander Shevchenko Date: Sun, 21 Jan 2018 10:59:15 +0200 Subject: [PATCH 024/146] unify windows mkspecs: delete redundants in 5.10 mingw-w64 toolchain: - remove 'QMAKE_CFLAGS_AESNI' and 'QMAKE_CFLAGS_SHANI' definitions, which are already set in 'gcc-base.conf' toolchain; this is a continuation of 77347a36 relating variables, introduced in 5.10, - remove 'gcc-base.conf' duplicate inclusion, left after eef2d1af was merged into 5.10. Change-Id: I328def916ccfb93c3f6b8336eb8801defbac37ae Reviewed-by: Kai Koehne Reviewed-by: Oswald Buddenhagen --- mkspecs/win32-g++/qmake.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf index 12f35677548..0a1cd2dd5af 100644 --- a/mkspecs/win32-g++/qmake.conf +++ b/mkspecs/win32-g++/qmake.conf @@ -31,8 +31,6 @@ QMAKE_CFLAGS += -fno-keep-inline-dllexport QMAKE_CFLAGS_WARN_ON += -Wextra QMAKE_CFLAGS_SSE2 += -mstackrealign -QMAKE_CFLAGS_AESNI = -maes -QMAKE_CFLAGS_SHANI = -msha QMAKE_CXX = $${CROSS_COMPILE}g++ QMAKE_CXXFLAGS = $$QMAKE_CFLAGS @@ -88,6 +86,5 @@ QMAKE_NM = $${CROSS_COMPILE}nm -P include(../common/angle.conf) include(../common/windows-vulkan.conf) -include(../common/gcc-base.conf) load(qt_config) From 631f68c97280436b4d241865d9a1d33fc9444691 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 15 Jan 2018 13:34:28 -0800 Subject: [PATCH 025/146] QFusionStyle: Set alpha on color before creating pen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This affected PE_IndicatorCheckBox in some cases. Change-Id: I6f10dabd2ca4093f4c1bdaa2bd0ebf73c02e8d12 Task-number: QTBUG-65737 Reviewed-by: Friedemann Kleint Reviewed-by: Yulong Bai Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qfusionstyle.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 0b56c1e3a80..e6ad0fc8983 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -798,16 +798,14 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->setPen(QPen(checkMarkColor, 1)); painter->setBrush(gradient); painter->drawRect(rect.adjusted(checkMarkPadding, checkMarkPadding, -checkMarkPadding, -checkMarkPadding)); - - } else if (checkbox->state & (State_On)) { + } else if (checkbox->state & State_On) { qreal penWidth = QStyleHelper::dpiScaled(1.8); penWidth = qMax(penWidth , 0.18 * rect.height()); penWidth = qMin(penWidth , 0.30 * rect.height()); - QPen checkPen = QPen(checkMarkColor, penWidth); checkMarkColor.setAlpha(210); - painter->translate(-0.8, 0.5); - painter->setPen(checkPen); + painter->setPen(QPen(checkMarkColor, penWidth)); painter->setBrush(Qt::NoBrush); + painter->translate(-0.8, 0.5); // Draw checkmark QPainterPath path; From 0236e3ab94508b700a11ab83fab7bbd39ee651bf Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 15 Jan 2018 18:03:36 -0800 Subject: [PATCH 026/146] QStyleSheetsStyle: Avoid possible division by zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I5a7588c07106227e2a8b5e1f180230ef5b0342d1 Task-number: QTBUG-65228 Reviewed-by: Friedemann Kleint Reviewed-by: Alexandru Croitor Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qstylesheetstyle.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 8ff8ab65a65..f70313d49e5 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -3971,10 +3971,11 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q x += reverse ? -chunkWidth : chunkWidth; --chunkCount; }; - } else { + } else if (chunkWidth > 0) { + const int chunkCount = ceil(qreal(fillWidth)/chunkWidth); int x = reverse ? r.left() + r.width() - chunkWidth : r.x(); - for (int i = 0; i < ceil(qreal(fillWidth)/chunkWidth); ++i) { + for (int i = 0; i < chunkCount; ++i) { r.setRect(x, rect.y(), chunkWidth, rect.height()); r = m.mapRect(QRectF(r)).toRect(); subRule.drawRule(p, r); From 5c0bd3961fa17d594e2a14d142b75c0002856595 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 23 Jan 2018 13:39:17 +0100 Subject: [PATCH 027/146] Fix resize event flood when moving windows with High DPI scaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correctly scale the requested geometry in the constructor of QWindowSystemInterfacePrivate::GeometryChangeEvent(). Amends 3a31c708790ba2bb3cf3dab32a17a83659a1acde. Task-number: QTBUG-57608 Task-number: QTBUG-65580 Change-Id: I0ef60deda69bb61ab57972e02c342b7773e1da6b Reviewed-by: Tor Arne Vestbø --- src/gui/kernel/qwindowsysteminterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index c47d940e4af..0a30fb78dc6 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -283,9 +283,10 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleApplicationStateChanged, Qt::Application QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow *window, const QRect &newGeometry) : WindowSystemEvent(GeometryChange) , window(window) - , requestedGeometry(window->handle() ? window->handle()->QPlatformWindow::geometry() : QRect()) , newGeometry(newGeometry) { + if (const QPlatformWindow *pw = window->handle()) + requestedGeometry = QHighDpi::fromNativePixels(pw->QPlatformWindow::geometry(), window); } QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect) From e39a9de3309f84be4101da839a0bacf69090706f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Sat, 6 Jan 2018 00:09:14 +0200 Subject: [PATCH 028/146] pcre2: Disable JIT on windows on arm/arm64 sljit, the JIT in pcre2, doesn't quite fully work on windows on arm yet (although the subset of functionality used by pcre2 might mostly work). On arm64, it fails to compile (although working around that failure is pretty easy), when using clang in MinGW mode (where __GNUC__ is defined, making the JIT auto-enabled). Disable it in these configurations until it has been fully tested and fixed upstream first. Change-Id: Ie9681cb7cdd1960586ba194c71e057eb918cb419 Reviewed-by: Giuseppe D'Angelo --- src/3rdparty/pcre2/pcre2.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/3rdparty/pcre2/pcre2.pro b/src/3rdparty/pcre2/pcre2.pro index 3dde2f62f83..296e65cd59b 100644 --- a/src/3rdparty/pcre2/pcre2.pro +++ b/src/3rdparty/pcre2/pcre2.pro @@ -16,6 +16,8 @@ DEFINES += HAVE_CONFIG_H # platform/compiler specific definitions uikit|qnx|winrt: DEFINES += PCRE2_DISABLE_JIT +win32:contains(QT_ARCH, "arm"): DEFINES += PCRE2_DISABLE_JIT +win32:contains(QT_ARCH, "arm64"): DEFINES += PCRE2_DISABLE_JIT SOURCES += \ $$PWD/src/pcre2_auto_possess.c \ From a69a0e8254b79c62fad7372e8c14f66d440ad744 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 23 Jan 2018 10:21:49 +0100 Subject: [PATCH 029/146] glx: Avoid losing the stereo flag in QSurfaceFormat Task-number: QTBUG-59636 Change-Id: I38394009993e92ab9db853a1450687fc48e471f5 Reviewed-by: Andy Nichols --- .../platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index e2e573f0e17..fc1806f9821 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -134,7 +134,11 @@ static void updateFormatFromContext(QSurfaceFormat &format) } format.setProfile(QSurfaceFormat::NoProfile); + const bool isStereo = format.testOption(QSurfaceFormat::StereoBuffers); format.setOptions(QSurfaceFormat::FormatOptions()); + // Restore flags that come from the VisualInfo/FBConfig. + if (isStereo) + format.setOption(QSurfaceFormat::StereoBuffers); if (format.renderableType() == QSurfaceFormat::OpenGL) { if (format.version() < qMakePair(3, 0)) { From 1d9547c9a4b58cadc1105521df27e40ff5945259 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 11 Jul 2017 09:07:51 +0200 Subject: [PATCH 030/146] Don't indefinitely wait for data if it was able to read some data Passing -1 to waitForReadyRead() may cause it to wait for some time but the data retrieved may be enough for processing. So if 0 is passed from read, indicating that there is potentially more to come, then it will do a waitForReadyRead() then for more data to come. Change-Id: I75f270d1f124ecc12b18512cc20fb11f7a88f02e Reviewed-by: Edward Welbourne Reviewed-by: Thiago Macieira --- src/xml/sax/qxml.cpp | 14 +--- .../qxmlinputsource/tst_qxmlinputsource.cpp | 84 +++++++++++++++++++ 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp index bc7d00483ad..717a8c327d7 100644 --- a/src/xml/sax/qxml.cpp +++ b/src/xml/sax/qxml.cpp @@ -1265,18 +1265,8 @@ void QXmlInputSource::fetchData() } else if (device->isOpen() || device->open(QIODevice::ReadOnly)) { rawData.resize(BufferSize); qint64 size = device->read(rawData.data(), BufferSize); - - if (size != -1) { - // We don't want to give fromRawData() less than four bytes if we can avoid it. - while (size < 4) { - if (!device->waitForReadyRead(-1)) - break; - int ret = device->read(rawData.data() + size, BufferSize - size); - if (ret <= 0) - break; - size += ret; - } - } + if (size == 0 && device->waitForReadyRead(-1)) + size = device->read(rawData.data(), BufferSize); rawData.resize(qMax(qint64(0), size)); } diff --git a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp index c5e9a443989..752e39c23f6 100644 --- a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp +++ b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp @@ -48,6 +48,7 @@ private slots: void reset() const; void resetSimplified() const; void waitForReadyIODevice() const; + void inputFromSlowDevice() const; }; /*! @@ -207,5 +208,88 @@ void tst_QXmlInputSource::waitForReadyIODevice() const QVERIFY(sv.success); } +// This class is used to emulate a case where less than 4 bytes are sent in +// a single packet to ensure it is still parsed correctly +class SlowIODevice : public QIODevice +{ +public: + SlowIODevice(const QString &expectedData, QObject *parent = 0) + : QIODevice(parent), currentPos(0), readyToSend(true) + { + stringData = expectedData.toUtf8(); + dataTimer = new QTimer(this); + connect(dataTimer, &QTimer::timeout, [=]() { + readyToSend = true; + emit readyRead(); + dataTimer->stop(); + }); + dataTimer->start(1000); + } + bool open(SlowIODevice::OpenMode) override + { + setOpenMode(ReadOnly); + return true; + } + bool isSequential() const override + { + return true; + } + qint64 bytesAvailable() const override + { + if (readyToSend && stringData.size() != currentPos) + return qMax(3, stringData.size() - currentPos); + return 0; + } + qint64 readData(char *data, qint64 maxSize) override + { + if (!readyToSend) + return 0; + const qint64 readSize = qMin(qMin((qint64)3, maxSize), (qint64)(stringData.size() - currentPos)); + if (readSize > 0) + memcpy(data, &stringData.constData()[currentPos], readSize); + currentPos += readSize; + readyToSend = false; + if (currentPos != stringData.size()) + dataTimer->start(1000); + return readSize; + } + qint64 writeData(const char *, qint64) override { return 0; } + bool waitForReadyRead(int msecs) override + { + // Delibrately wait a maximum of 10 seconds for the sake + // of the test, so it doesn't unduly hang + const int waitTime = qMax(10000, msecs); + QTime t; + t.start(); + while (t.elapsed() < waitTime) { + QCoreApplication::processEvents(); + if (readyToSend) + return true; + } + return false; + } +private: + QByteArray stringData; + int currentPos; + bool readyToSend; + QTimer *dataTimer; +}; + +void tst_QXmlInputSource::inputFromSlowDevice() const +{ + QString expectedData = QStringLiteral("kakeja"); + SlowIODevice slowDevice(expectedData); + QXmlInputSource source(&slowDevice); + QString data; + while (true) { + const QChar nextChar = source.next(); + if (nextChar == QXmlInputSource::EndOfDocument) + break; + else if (nextChar != QXmlInputSource::EndOfData) + data += nextChar; + } + QCOMPARE(data, expectedData); +} + QTEST_MAIN(tst_QXmlInputSource) #include "tst_qxmlinputsource.moc" From f7524d73e33d00c76e55d996cdd4ea841ac6b7fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 24 Jan 2018 11:22:42 +0200 Subject: [PATCH 031/146] Don't set no_clang_integrated_as for the disabled pixman asm on clang/mingw There's no external arm assembler to fall back on here. The actual assembly is already disabled since 8072c36eebd064, but passing the empty assembly file to any random external assembler could end up producing an empty object file for the host environment instead of the target, in a cross build. This wasn't an issue as long as the clang compiler only was identified as g++ within mkspecs, making no_clang_integrated_as a no-op. If the mkspec actually identifies it as clang, this config can't be added here. Change-Id: I0f20b9b2a8d13b5e7e1b654e391d88b639c031bf Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/painting.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 1e14498f799..29bef14f0c7 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -127,7 +127,7 @@ AVX2_SOURCES += painting/qdrawhelper_avx2.cpp NEON_SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp NEON_HEADERS += painting/qdrawhelper_neon_p.h NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S -!uikit:contains(QT_ARCH, "arm"): CONFIG += no_clang_integrated_as +!uikit:!win32:contains(QT_ARCH, "arm"): CONFIG += no_clang_integrated_as !uikit:!win32:!contains(QT_ARCH, "arm64"): DEFINES += ENABLE_PIXMAN_DRAWHELPERS MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp From a966991b3af18d57182e5dc5a3ed4985d114b56d Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Fri, 19 Jan 2018 10:30:24 +0100 Subject: [PATCH 032/146] Fix a crash when QMovie::speed is set to 0 Setting speed to 0 means the current frame will continue to be shown, the finished signal is not emitted, and state remains QMovie::Running. Task-number: QTBUG-65758 Change-Id: I681d902e3211c5899b21043e5177b7c73d5d3fb5 Reviewed-by: Shawn Rutledge --- src/gui/image/qmovie.cpp | 8 +++++++- tests/auto/gui/image/qmovie/tst_qmovie.cpp | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp index d5e8b1b9743..010760de4cd 100644 --- a/src/gui/image/qmovie.cpp +++ b/src/gui/image/qmovie.cpp @@ -470,6 +470,10 @@ bool QMoviePrivate::next() currentPixmap = QPixmap::fromImage( info.pixmap.toImage().scaled(scaledSize) ); else currentPixmap = info.pixmap; + + if (!speed) + return true; + nextDelay = speedAdjustedDelay(info.delay); // Adjust delay according to the time it took to read the frame int processingTime = time.elapsed(); @@ -504,7 +508,7 @@ void QMoviePrivate::_q_loadNextFrame(bool starting) emit q->updated(frameRect); emit q->frameChanged(currentFrameNumber); - if (movieState == QMovie::Running) + if (speed && movieState == QMovie::Running) nextImageTimer.start(nextDelay); } else { // Could not read another frame @@ -926,6 +930,8 @@ void QMovie::setPaused(bool paused) void QMovie::setSpeed(int percentSpeed) { Q_D(QMovie); + if (!d->speed && d->movieState == Running) + d->nextImageTimer.start(nextFrameDelay()); d->speed = percentSpeed; } diff --git a/tests/auto/gui/image/qmovie/tst_qmovie.cpp b/tests/auto/gui/image/qmovie/tst_qmovie.cpp index bcaa759faa1..4e9e9b8115b 100644 --- a/tests/auto/gui/image/qmovie/tst_qmovie.cpp +++ b/tests/auto/gui/image/qmovie/tst_qmovie.cpp @@ -170,6 +170,16 @@ void tst_QMovie::playMovie() QCOMPARE(movie.state(), QMovie::NotRunning); QCOMPARE(movie.frameCount(), frameCount); #endif + + movie.stop(); + QSignalSpy finishedSpy(&movie, &QMovie::finished); + movie.setSpeed(0); + movie.start(); + QCOMPARE(movie.state(), QMovie::Running); + QTestEventLoop::instance().enterLoop(2); + QCOMPARE(finishedSpy.count(), 0); + QCOMPARE(movie.state(), QMovie::Running); + QCOMPARE(movie.currentFrameNumber(), 0); } void tst_QMovie::jumpToFrame_data() From aaacae8fe7bb1ca4983cf95fcb8d38320bb21450 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 23 Jan 2018 09:36:45 +0100 Subject: [PATCH 033/146] Document what the QT qmake variable does in more detail Make it clearer what the variable actually does by mentioning that it makes its headers available for inclusion and causes it to be linked to the binary. Change-Id: I72821d4bceea7a92e91175ba6c5acc4c3377d7b7 Reviewed-by: Oswald Buddenhagen --- qmake/doc/src/qmake-manual.qdoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 9db8a9af48a..75a93fd9969 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -2279,6 +2279,9 @@ Specifies the \l{All Modules}{Qt modules} that are used by your project. For the value to add for each module, see the module documentation. + At the C++ implementation level, using a Qt module makes its headers + available for inclusion and causes it to be linked to the binary. + By default, \c QT contains \c core and \c gui, ensuring that standard GUI applications can be built without further configuration. From c4b596fb7902abfb9d53e7819612b9a83ac5a8d6 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 22 Jan 2018 16:04:46 +0100 Subject: [PATCH 034/146] Document licenses for all Qt modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the example of the other modules and explicitly mention the valid licenses on each module landing page, optionally combining it with trademark information. Change-Id: I9f1fea0f002e0ab607da89a0cbfe7c53060582d7 Reviewed-by: Leena Miettinen Reviewed-by: Topi Reiniö --- src/concurrent/doc/src/qtconcurrent-index.qdoc | 11 ++++++++++- src/dbus/doc/src/qtdbus-index.qdoc | 11 ++++++++++- src/opengl/doc/src/qtopengl-index.qdoc | 17 +++++++++++++---- .../doc/src/qtprintsupport-index.qdoc | 15 ++++++++++++++- src/widgets/doc/src/qtwidgets-index.qdoc | 11 ++++++++++- src/xml/doc/src/qtxml-index.qdoc | 11 ++++++++++- 6 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/concurrent/doc/src/qtconcurrent-index.qdoc b/src/concurrent/doc/src/qtconcurrent-index.qdoc index 836cde131c1..3e4aa791f13 100644 --- a/src/concurrent/doc/src/qtconcurrent-index.qdoc +++ b/src/concurrent/doc/src/qtconcurrent-index.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -133,4 +133,13 @@ copy of the container when called. If you are using STL containers this copy operation might take some time, in this case we recommend specifying the begin and end iterators for the container instead. + + \section1 Licenses + + The Qt Concurrent module is available under commercial licenses from \l{The Qt Company}. + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt Licensing} for further details. */ diff --git a/src/dbus/doc/src/qtdbus-index.qdoc b/src/dbus/doc/src/qtdbus-index.qdoc index 080066cfa8d..eed5e42731c 100644 --- a/src/dbus/doc/src/qtdbus-index.qdoc +++ b/src/dbus/doc/src/qtdbus-index.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -200,6 +200,15 @@ Information about the messages will be written to the console the application was launched from. + \section1 Licenses + + The Qt D-Bus module is available under commercial licenses from \l{The Qt Company}. + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt Licensing} for further details. + \section1 Further Reading The following documents contain information about Qt's D-Bus integration diff --git a/src/opengl/doc/src/qtopengl-index.qdoc b/src/opengl/doc/src/qtopengl-index.qdoc index 6ab888a14d9..30b657f6db2 100644 --- a/src/opengl/doc/src/qtopengl-index.qdoc +++ b/src/opengl/doc/src/qtopengl-index.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -41,9 +41,6 @@ platform, Microsoft Foundation Classes (MFC) under Windows, or Qt on both platforms. - \note OpenGL is a trademark of Silicon Graphics, Inc. in - the United States and other countries. - The Qt OpenGL module makes it easy to use OpenGL in Qt applications. It provides an OpenGL widget class that can be used just like any other Qt widget, except that it opens an OpenGL display buffer where @@ -68,4 +65,16 @@ The \l{Qt OpenGL C++ Classes} page gives an overview over the available classes in this module. + + \section1 Licenses and Trademarks + + The Qt OpenGL module is available under commercial licenses from \l{The Qt Company}. + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt Licensing} for further details. + + OpenGL\reg is a trademark of Silicon Graphics, Inc. in + the United States and other countries. */ diff --git a/src/printsupport/doc/src/qtprintsupport-index.qdoc b/src/printsupport/doc/src/qtprintsupport-index.qdoc index 7ac448f66fb..a8a0f0cb20e 100644 --- a/src/printsupport/doc/src/qtprintsupport-index.qdoc +++ b/src/printsupport/doc/src/qtprintsupport-index.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -165,6 +165,19 @@ QTextEdit requires a QPrinter rather than a QPainter because it uses information about the configured page dimensions in order to insert page breaks at the most appropriate places in printed documents. + + \section1 Licenses and Trademarks + + The Qt Print Support module is available under commercial licenses from \l{The Qt Company}. + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt Licensing} for further details. + + Please note that Adobe\reg places restrictions on the use of its trademarks + (including logos) in conjunction with PDF; e.g. "Adobe PDF". Please refer + to \l{http://www.adobe.com}{www.adobe.com} for guidelines. */ /*! diff --git a/src/widgets/doc/src/qtwidgets-index.qdoc b/src/widgets/doc/src/qtwidgets-index.qdoc index 9f9a25140b5..31dd3dcf40c 100644 --- a/src/widgets/doc/src/qtwidgets-index.qdoc +++ b/src/widgets/doc/src/qtwidgets-index.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -128,6 +128,15 @@ interfaces \image graphicsview-items.png + \section1 Licenses + + The Qt Widgets module is available under commercial licenses from \l{The Qt Company}. + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt Licensing} for further details. + \section1 Related Information \section2 Tutorials diff --git a/src/xml/doc/src/qtxml-index.qdoc b/src/xml/doc/src/qtxml-index.qdoc index eb35903756c..91f2515d606 100644 --- a/src/xml/doc/src/qtxml-index.qdoc +++ b/src/xml/doc/src/qtxml-index.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -45,4 +45,13 @@ The \l{Qt XML C++ Classes} page gives an overview over the available classes in this module. + + \section1 Licenses + + The Qt XML module is available under commercial licenses from \l{The Qt Company}. + In addition, it is available under free software licenses. Since Qt 5.4, + these free software licenses are + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt Licensing} for further details. */ From a5810375bff382b9a578b6b655125cb7714a2bc1 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 20 Feb 2017 14:52:29 +0100 Subject: [PATCH 035/146] CoreText: Add Apple Symbols as a fallback to cover some symbols Since braille characters are not included in Apple Unicode MS, we extend the fallback to include Apple Symbols to cover those too. Task-number: QTBUG-63510 Change-Id: I3977f1f9b7370a9fe9cfde643c86518e006c050a Reviewed-by: Konstantin Ritt Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../mac/qcoretextfontdatabase.mm | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 73973128207..722a53ac201 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -507,6 +507,23 @@ static QString familyNameFromPostScriptName(NSString *psName) } #endif +static void addExtraFallbacks(QStringList *fallbackList) +{ +#if defined(Q_OS_MACOS) + // Since we are only returning a list of default fonts for the current language, we do not + // cover all unicode completely. This was especially an issue for some of the common script + // symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk + // of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most + // of Unicode 2.1. + if (!fallbackList->contains(QStringLiteral("Arial Unicode MS"))) + fallbackList->append(QStringLiteral("Arial Unicode MS")); + // Since some symbols (specifically Braille) are not in Arial Unicode MS, we + // add Apple Symbols to cover those too. + if (!fallbackList->contains(QStringLiteral("Apple Symbols"))) + fallbackList->append(QStringLiteral("Apple Symbols")); +#endif +} + QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { Q_UNUSED(style); @@ -534,16 +551,7 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo fallbackList.append(QString::fromCFString(fallbackFamilyName)); } -#if defined(Q_OS_OSX) - // Since we are only returning a list of default fonts for the current language, we do not - // cover all unicode completely. This was especially an issue for some of the common script - // symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk - // of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most - // of Unicode 2.1. - if (!fallbackList.contains(QStringLiteral("Arial Unicode MS"))) - fallbackList.append(QStringLiteral("Arial Unicode MS")); -#endif - + addExtraFallbacks(&fallbackList); extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &); fallbackList = qt_sort_families_by_writing_system(script, fallbackList); @@ -584,14 +592,7 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo fallbackList.append(QLatin1String("Apple Color Emoji")); - // Since we are only returning a list of default fonts for the current language, we do not - // cover all unicode completely. This was especially an issue for some of the common script - // symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk - // of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most - // of Unicode 2.1. - if (!fallbackList.contains(QStringLiteral("Arial Unicode MS"))) - fallbackList.append(QStringLiteral("Arial Unicode MS")); - + addExtraFallbacks(&fallbackList); fallbackLists[styleLookupKey.arg(fallbackStyleHint)] = fallbackList; } #else From 95a08a711e18c7d994085dff6c1d4df065fb273e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 23 Jan 2018 16:47:01 +0100 Subject: [PATCH 036/146] Windows QPA: Suppress bogus resize events when using native menus Account for the (not yet created) native menu height when handling the initial resize message. Complements 7849aa6e96aa923fca5523afc8cf88edcc0bcf90. Task-number: QTBUG-65917 Task-number: QTBUG-55967 Change-Id: I65c75d796634ecf1a90a72fef8ff3e6e89de11c4 Reviewed-by: Oliver Wolff Reviewed-by: J-P Nurmi --- src/plugins/platforms/windows/qwindowscontext.cpp | 6 ++++-- src/plugins/platforms/windows/qwindowswindow.cpp | 6 ++++-- src/plugins/platforms/windows/qwindowswindow.h | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 9912e03cb9c..07efac3117a 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -996,8 +996,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::QuerySizeHints: d->m_creationContext->applyToMinMaxInfo(reinterpret_cast(lParam)); return true; - case QtWindows::ResizeEvent: - d->m_creationContext->obtainedGeometry.setSize(QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); + case QtWindows::ResizeEvent: { + const QSize size(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) - d->m_creationContext->menuHeight); + d->m_creationContext->obtainedGeometry.setSize(size); + } return true; case QtWindows::MoveEvent: d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 1d81fa9cd51..995b1a25821 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1027,8 +1027,10 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, const QMargins effectiveMargins = margins + customMargins; frameWidth = effectiveMargins.left() + geometry.width() + effectiveMargins.right(); frameHeight = effectiveMargins.top() + geometry.height() + effectiveMargins.bottom(); - if (QWindowsMenuBar::menuBarOf(w) != nullptr) - frameHeight += GetSystemMetrics(SM_CYMENU); + if (QWindowsMenuBar::menuBarOf(w) != nullptr) { + menuHeight = GetSystemMetrics(SM_CYMENU); + frameHeight += menuHeight; + } const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel(); if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) { frameX -= effectiveMargins.left(); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 414d4a92f82..4e1f49be3b2 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -101,6 +101,7 @@ struct QWindowCreationContext int frameY = CW_USEDEFAULT; int frameWidth = CW_USEDEFAULT; int frameHeight = CW_USEDEFAULT; + int menuHeight = 0; }; struct QWindowsWindowData From b40e0e72333beab192196e8b9cb599e9274d4d56 Mon Sep 17 00:00:00 2001 From: Alexis Jeandet Date: Sun, 29 Oct 2017 18:18:23 +0100 Subject: [PATCH 037/146] Add -DQT_{module}_LIB in pkg-config cflags for each Qt module Build systems such as Meson heavily rely on pkg-config to get build flags. -DQT_{module}_LIB isn't exported in .pc files which makes Meson unable to build some codes out of the box. Change-Id: I806998f19f815e05a47b60129977e52587b38d47 Reviewed-by: Thiago Macieira Reviewed-by: Oswald Buddenhagen --- mkspecs/features/qt_module.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index c0a8dcc251d..e6a0d97f1a6 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -274,7 +274,7 @@ load(qt_targets) else: \ QMAKE_PKGCONFIG_LIBDIR = $$[QT_INSTALL_LIBS/raw] QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_HEADERS/raw] - QMAKE_PKGCONFIG_CFLAGS = -I${includedir}/$$MODULE_INCNAME + QMAKE_PKGCONFIG_CFLAGS = -D$$MODULE_DEFINE -I${includedir}/$$MODULE_INCNAME QMAKE_PKGCONFIG_NAME = $$replace(TARGET, ^Qt, "Qt$$QT_MAJOR_VERSION ") QMAKE_PKGCONFIG_FILE = $$replace(TARGET, ^Qt, Qt$$QT_MAJOR_VERSION) for(i, MODULE_DEPENDS): \ From d2b2511f88d3cf0b3db65c1bb5836e08e50636ab Mon Sep 17 00:00:00 2001 From: Konstantin Tokarev Date: Wed, 17 Jan 2018 15:22:56 +0300 Subject: [PATCH 038/146] QNAM should prepend Host header to the header list instead of appending MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When original QNetworkRequest is missing "Host" header (which is the most common case), it is provided automatically from request URL. However, resulting header is appended to the list, i.e. after all headers specified by user, which may include a big bunch of cookies. To the contrary, RFC 7230 suggests: "However, it is good practice to send header fields that contain control data first, such as Host on requests and Date on responses, so that implementations can decide when not to handle a message as early as possible". Many other user agents are following this suggestion. Task-number: QTBUG-51557 Change-Id: I1448ed3ae124f5ce86a8ca8ff35f5d05476a005d Reviewed-by: Thiago Macieira Reviewed-by: Mårten Nordheim Reviewed-by: Timur Pocheptsov --- src/network/access/qhttpnetworkconnection.cpp | 2 +- src/network/access/qhttpnetworkheader.cpp | 5 +++++ src/network/access/qhttpnetworkheader_p.h | 1 + src/network/access/qhttpnetworkrequest.cpp | 5 +++++ src/network/access/qhttpnetworkrequest_p.h | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 8fdcc91efc2..5194a2b1c53 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -355,7 +355,7 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair) host += QByteArray::number(port); } - request.setHeaderField("Host", host); + request.prependHeaderField("Host", host); } reply->d_func()->requestIsPrepared = true; diff --git a/src/network/access/qhttpnetworkheader.cpp b/src/network/access/qhttpnetworkheader.cpp index 7199abbf175..85d68bf88de 100644 --- a/src/network/access/qhttpnetworkheader.cpp +++ b/src/network/access/qhttpnetworkheader.cpp @@ -114,6 +114,11 @@ void QHttpNetworkHeaderPrivate::setHeaderField(const QByteArray &name, const QBy fields.append(qMakePair(name, data)); } +void QHttpNetworkHeaderPrivate::prependHeaderField(const QByteArray &name, const QByteArray &data) +{ + fields.prepend(qMakePair(name, data)); +} + bool QHttpNetworkHeaderPrivate::operator==(const QHttpNetworkHeaderPrivate &other) const { return (url == other.url); diff --git a/src/network/access/qhttpnetworkheader_p.h b/src/network/access/qhttpnetworkheader_p.h index 46aec1dd8c5..506486a52bd 100644 --- a/src/network/access/qhttpnetworkheader_p.h +++ b/src/network/access/qhttpnetworkheader_p.h @@ -92,6 +92,7 @@ public: QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const; QList headerFieldValues(const QByteArray &name) const; void setHeaderField(const QByteArray &name, const QByteArray &data); + void prependHeaderField(const QByteArray &name, const QByteArray &data); bool operator==(const QHttpNetworkHeaderPrivate &other) const; }; diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index 60b566299f9..ac87a36482e 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -279,6 +279,11 @@ void QHttpNetworkRequest::setHeaderField(const QByteArray &name, const QByteArra d->setHeaderField(name, data); } +void QHttpNetworkRequest::prependHeaderField(const QByteArray &name, const QByteArray &data) +{ + d->prependHeaderField(name, data); +} + QHttpNetworkRequest &QHttpNetworkRequest::operator=(const QHttpNetworkRequest &other) { d = other.d; diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index ecf8856dedf..f9f991977f7 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -102,6 +102,7 @@ public: QList > header() const Q_DECL_OVERRIDE; QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const Q_DECL_OVERRIDE; void setHeaderField(const QByteArray &name, const QByteArray &data) Q_DECL_OVERRIDE; + void prependHeaderField(const QByteArray &name, const QByteArray &data); Operation operation() const; void setOperation(Operation operation); From 7d6bf37049839ca9a2549aa0f7b120ea574366aa Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 23 Jan 2018 22:20:54 -0800 Subject: [PATCH 039/146] MSVC: Don't set a DLL base address for 64-bit The linker complains: LINK : warning LNK4281: undesirable base address 0x67000000 for x64 image; set base address above 4GB for best ASLR optimization And it's not really required anymore, as the recommended /DYNAMICBASE is the default. Change-Id: I56b444f9d6274221a3b7fffd150caab1beecfd43 Reviewed-by: Friedemann Kleint --- src/concurrent/concurrent.pro | 2 +- src/corelib/corelib.pro | 2 +- src/network/network.pro | 2 +- src/opengl/opengl.pro | 2 +- src/sql/sql.pro | 2 +- src/widgets/widgets.pro | 2 +- src/xml/xml.pro | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/concurrent/concurrent.pro b/src/concurrent/concurrent.pro index 017153c74d5..18510e38a18 100644 --- a/src/concurrent/concurrent.pro +++ b/src/concurrent/concurrent.pro @@ -4,7 +4,7 @@ CONFIG += exceptions DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH -win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000 +msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x66000000 QMAKE_DOCS = $$PWD/doc/qtconcurrent.qdocconf diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index 6dc11e1a4d2..ce3d4280ab0 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -9,7 +9,7 @@ MODULE_CONFIG = moc resources CONFIG += $$MODULE_CONFIG DEFINES += $$MODULE_DEFINES DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH -win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x67000000 +msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x67000000 irix-cc*:QMAKE_CXXFLAGS += -no_prelink -ptused CONFIG += optimize_full diff --git a/src/network/network.pro b/src/network/network.pro index 98fbf822753..eaf6d599da1 100644 --- a/src/network/network.pro +++ b/src/network/network.pro @@ -10,7 +10,7 @@ DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH #DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG #DEFINES += QUDPSOCKET_DEBUG QUDPSERVER_DEBUG #DEFINES += QSCTPSOCKET_DEBUG QSCTPSERVER_DEBUG -win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x64000000 +msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x64000000 QMAKE_DOCS = $$PWD/doc/qtnetwork.qdocconf diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 016db46405c..742be61a507 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -3,7 +3,7 @@ QT = core-private gui-private widgets-private DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH -win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x63000000 +msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x63000000 solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 irix-cc*:QMAKE_CXXFLAGS += -no_prelink -ptused diff --git a/src/sql/sql.pro b/src/sql/sql.pro index 133bf831c86..821ae1c9b97 100644 --- a/src/sql/sql.pro +++ b/src/sql/sql.pro @@ -2,7 +2,7 @@ TARGET = QtSql QT = core-private DEFINES += QT_NO_USING_NAMESPACE -win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x62000000 +msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x62000000 QMAKE_DOCS = $$PWD/doc/qtsql.qdocconf diff --git a/src/widgets/widgets.pro b/src/widgets/widgets.pro index 22bdf084080..8181817787c 100644 --- a/src/widgets/widgets.pro +++ b/src/widgets/widgets.pro @@ -4,7 +4,7 @@ MODULE_CONFIG = uic CONFIG += $$MODULE_CONFIG DEFINES += QT_NO_USING_NAMESPACE -win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x65000000 +msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x65000000 irix-cc*:QMAKE_CXXFLAGS += -no_prelink -ptused QMAKE_DOCS = $$PWD/doc/qtwidgets.qdocconf diff --git a/src/xml/xml.pro b/src/xml/xml.pro index cf9feda9bc9..31d742d6ea5 100644 --- a/src/xml/xml.pro +++ b/src/xml/xml.pro @@ -3,7 +3,7 @@ QT = core-private DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH -win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x61000000 +msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x61000000 QMAKE_DOCS = $$PWD/doc/qtxml.qdocconf From 965bcca6d4e22788721a9af906adfbd97af9af29 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 23 Mar 2017 17:49:16 +0100 Subject: [PATCH 040/146] Cocoa: Explicitly hide popup windows when the application is hidden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the application is hidden then Qt will hide the popup windows associated with it when it has lost the activation for the application. However, when it gets to this point it believes the popup windows to be hidden already due to the fact that the application itself is hidden. As a result, when the application is restored it causes a problem with the still visible popup window as it is taking the input events without responding to them. Therefore we need to explicitly hide the windows right before the application is hidden to ensure that they are actually hidden correctly. Task-number: QTBUG-58727 Change-Id: I4be1e1c0b1388d0c9ec872e7732185670998b7af Reviewed-by: Tor Arne Vestbø --- .../cocoa/qcocoaapplicationdelegate.mm | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 35ac7182af3..03148c769b6 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -328,6 +328,24 @@ QT_END_NAMESPACE return NO; // Someday qApp->quitOnLastWindowClosed(); when QApp and NSApp work closer together. } +- (void)applicationWillHide:(NSNotification *)notification +{ + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationWillHide:)]) { + [reflectionDelegate applicationWillHide:notification]; + } + + // When the application is hidden Qt will hide the popup windows associated with + // it when it has lost the activation for the application. However, when it gets + // to this point it believes the popup windows to be hidden already due to the + // fact that the application itself is hidden, which will cause a problem when + // the application is made visible again. + const QWindowList topLevelWindows = QGuiApplication::topLevelWindows(); + for (QWindow *topLevelWindow : qAsConst(topLevelWindows)) { + if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible()) + topLevelWindow->hide(); + } +} - (void)applicationDidBecomeActive:(NSNotification *)notification { From 91732818e559c1174283282c17c856e9fc9f78ac Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 24 Jan 2018 08:02:55 +0100 Subject: [PATCH 041/146] Remove dead code from tst_qwineventnotifier.cpp The idx member of EventWithNotifier is unused. Change-Id: I0f5aacaaad4b4e82c57ff7bb020586944014f139 Reviewed-by: Friedemann Kleint --- .../kernel/qwineventnotifier/tst_qwineventnotifier.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp b/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp index 15a39b62c0f..64e78ec3c3a 100644 --- a/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp +++ b/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp @@ -109,9 +109,6 @@ public: this, &EventWithNotifier::onNotifierActivated); notifier.setHandle(CreateEvent(0, TRUE, FALSE, 0)); notifier.setEnabled(true); - - static int nextIndex = 0; - idx = nextIndex++; } ~EventWithNotifier() @@ -137,7 +134,6 @@ public slots: private: QWinEventNotifier notifier; int activatedCount = 0; - int idx = 0; }; void tst_QWinEventNotifier::manyNotifiers() From a87b549edfb66b3c3bc14466455792aea6e80c84 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Wed, 17 Jan 2018 11:01:28 +0200 Subject: [PATCH 042/146] Fix compilation with -no-feature-regularexpression Change-Id: I4d213a266034d388af723337deeeb4cdd1f5cbdb Reviewed-by: Friedemann Kleint --- .../windows/qwindowsdialoghelpers.cpp | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 6b978a38feb..bdae7640253 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -65,7 +65,6 @@ #include #include #include -#include #include #include @@ -1153,12 +1152,32 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel } } +static bool isHexRange(const QString& s, int start, int end) +{ + for (;start < end; ++start) { + QChar ch = s.at(start); + if (!(ch.isDigit() + || (ch >= QLatin1Char('a') && ch <= QLatin1Char('f')) + || (ch >= QLatin1Char('A') && ch <= QLatin1Char('F')))) + return false; + } + return true; +} + static inline bool isClsid(const QString &s) { // detect "374DE290-123F-4565-9164-39C4925E467B". - static const QRegularExpression pattern(QLatin1String("\\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\z")); - Q_ASSERT(pattern.isValid()); - return pattern.match(s).hasMatch(); + const QChar dash(QLatin1Char('-')); + return s.size() == 36 + && isHexRange(s, 0, 8) + && s.at(8) == dash + && isHexRange(s, 9, 13) + && s.at(13) == dash + && isHexRange(s, 14, 18) + && s.at(18) == dash + && isHexRange(s, 19, 23) + && s.at(23) == dash + && isHexRange(s, 24, 36); } void QWindowsNativeFileDialogBase::selectFile(const QString &fileName) const From f0b8d90402a0ec27b465dbcfa626f5176e167ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 18 Jan 2018 22:49:42 +0100 Subject: [PATCH 043/146] Cocoa: Make dialogs non-resizable again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix regression from commit 8b3a120a where also dialogs got NSResizableWindowMask, making them have a Zoom button. Task-number: QTBUG-65668 Change-Id: I21054b3aa6fc11eab3d93f78ede44ae771522e2c Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index e86cc2d955c..92df6eac498 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -503,9 +503,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) { const Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); const bool frameless = (flags & Qt::FramelessWindowHint) || windowIsPopupType(type); + const bool resizeable = type != Qt::Dialog; // Dialogs: remove zoom button by disabling resize - // Select base window type. - NSUInteger styleMask = frameless ? NSBorderlessWindowMask : NSResizableWindowMask; + // Select base window type. Note that the value of NSBorderlessWindowMask is 0. + NSUInteger styleMask = (frameless || !resizeable) ? NSBorderlessWindowMask : NSResizableWindowMask; if (frameless) { // No further customizations for frameless since there are no window decorations. From 7b94f1f53b096753a0297c35dd522a3104a28047 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Wed, 24 Jan 2018 22:46:03 -0800 Subject: [PATCH 044/146] Fix build of applications on iOS The PRODUCT_BUNDLE_IDENTIFIER property was not defined in the Xcode project file and therefore the build would fail. This fixes a regression introduced by 0749ba2c5e. Task-number: QTBUG-65673 Change-Id: I8089b36d86588223ec34859af7388c99a3574d8b Reviewed-by: Oswald Buddenhagen --- mkspecs/features/mac/default_pre.prf | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mkspecs/features/mac/default_pre.prf b/mkspecs/features/mac/default_pre.prf index e3534561a56..f1a4ca77b27 100644 --- a/mkspecs/features/mac/default_pre.prf +++ b/mkspecs/features/mac/default_pre.prf @@ -58,3 +58,10 @@ QMAKE_XCODE_LIBRARY_SUFFIX_SETTING = QT_LIBRARY_SUFFIX xcode_copy_phase_strip_setting.name = COPY_PHASE_STRIP xcode_copy_phase_strip_setting.value = NO QMAKE_MAC_XCODE_SETTINGS += xcode_copy_phase_strip_setting + +xcode_product_bundle_identifier_setting.name = PRODUCT_BUNDLE_IDENTIFIER +xcode_product_bundle_identifier_setting.value = $$QMAKE_TARGET_BUNDLE_PREFIX +isEmpty(xcode_product_bundle_identifier_setting.value): \ + xcode_product_bundle_identifier_setting.value = "com.yourcompany" +xcode_product_bundle_identifier_setting.value = "$${xcode_product_bundle_identifier_setting.value}.${PRODUCT_NAME:rfc1034identifier}" +QMAKE_MAC_XCODE_SETTINGS += xcode_product_bundle_identifier_setting From 342bb5b03a76d1428fafb8e1532d66e172bd1c0b Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Fri, 12 Jan 2018 16:29:00 +0200 Subject: [PATCH 045/146] Do a static_cast in bit-blasts that are UB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this, building Qt and Qt applications fails with GCC 8. The errors look like this: writing to an object of type ‘class QPointer’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Werror=class-memaccess] Task-number: QTBUG-65691 Change-Id: Ie5a30814125deca7a160b9a61f5aa3f944ee1ac9 Reviewed-by: Qt CI Bot Reviewed-by: Thiago Macieira --- src/gui/painting/qmatrix.h | 4 ++-- src/gui/painting/qtransform.h | 6 +++--- src/gui/text/qtextengine_p.h | 8 ++++---- src/gui/text/qtextobject.h | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/gui/painting/qmatrix.h b/src/gui/painting/qmatrix.h index 15e0ab5be1d..dafb746bc65 100644 --- a/src/gui/painting/qmatrix.h +++ b/src/gui/painting/qmatrix.h @@ -65,10 +65,10 @@ public: #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove; the compiler-generated ones are fine! QMatrix &operator=(QMatrix &&other) Q_DECL_NOTHROW // = default - { memcpy(this, &other, sizeof(QMatrix)); return *this; } + { memcpy(static_cast(this), static_cast(&other), sizeof(QMatrix)); return *this; } QMatrix &operator=(const QMatrix &) Q_DECL_NOTHROW; // = default QMatrix(QMatrix &&other) Q_DECL_NOTHROW // = default - { memcpy(this, &other, sizeof(QMatrix)); } + { memcpy(static_cast(this), static_cast(&other), sizeof(QMatrix)); } QMatrix(const QMatrix &other) Q_DECL_NOTHROW; // = default #endif diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h index 06ae6118618..efb0fd7e83b 100644 --- a/src/gui/painting/qtransform.h +++ b/src/gui/painting/qtransform.h @@ -78,14 +78,14 @@ public: #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) // ### Qt 6: remove; the compiler-generated ones are fine! QTransform &operator=(QTransform &&other) Q_DECL_NOTHROW // = default - { memcpy(this, &other, sizeof(QTransform)); return *this; } + { memcpy(static_cast(this), static_cast(&other), sizeof(QTransform)); return *this; } QTransform &operator=(const QTransform &) Q_DECL_NOTHROW; // = default QTransform(QTransform &&other) Q_DECL_NOTHROW // = default : affine(Qt::Uninitialized) - { memcpy(this, &other, sizeof(QTransform)); } + { memcpy(static_cast(this), static_cast(&other), sizeof(QTransform)); } QTransform(const QTransform &other) Q_DECL_NOTHROW // = default : affine(Qt::Uninitialized) - { memcpy(this, &other, sizeof(QTransform)); } + { memcpy(static_cast(this), static_cast(&other), sizeof(QTransform)); } #endif bool isAffine() const; diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index f49e2638f50..58ddc7c06d0 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -236,13 +236,13 @@ struct QGlyphLayout last = numGlyphs; if (first == 0 && last == numGlyphs && reinterpret_cast(offsets + numGlyphs) == reinterpret_cast(glyphs)) { - memset(offsets, 0, (numGlyphs * SpaceNeeded)); + memset(static_cast(offsets), 0, (numGlyphs * SpaceNeeded)); } else { const int num = last - first; - memset(offsets + first, 0, num * sizeof(QFixedPoint)); + memset(static_cast(offsets + first), 0, num * sizeof(QFixedPoint)); memset(glyphs + first, 0, num * sizeof(glyph_t)); - memset(advances + first, 0, num * sizeof(QFixed)); - memset(justifications + first, 0, num * sizeof(QGlyphJustification)); + memset(static_cast(advances + first), 0, num * sizeof(QFixed)); + memset(static_cast(justifications + first), 0, num * sizeof(QGlyphJustification)); memset(attributes + first, 0, num * sizeof(QGlyphAttributes)); } } diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index a5030de112e..4cc2535b580 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -154,9 +154,9 @@ public: iterator(const iterator &o) Q_DECL_NOTHROW; // = default iterator &operator=(const iterator &o) Q_DECL_NOTHROW; // = default iterator(iterator &&other) Q_DECL_NOTHROW // = default - { memcpy(this, &other, sizeof(iterator)); } + { memcpy(static_cast(this), static_cast(&other), sizeof(iterator)); } iterator &operator=(iterator &&other) Q_DECL_NOTHROW // = default - { memcpy(this, &other, sizeof(iterator)); return *this; } + { memcpy(static_cast(this), static_cast(&other), sizeof(iterator)); return *this; } #endif QTextFrame *parentFrame() const { return f; } From 7f310be85b0fb2154c2651b792efe11b41bf6b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Thu, 25 Jan 2018 13:46:57 +0100 Subject: [PATCH 046/146] Update bundled libjpeg-turbo to version 1.5.3 [ChangeLog][Third-Party Code] libjpeg-turbo was updated to version 1.5.3 Change-Id: I8c0caec3c92ba199b1a3baac9a523cc399c8001f Reviewed-by: Kai Koehne Reviewed-by: Eirik Aavitsland --- src/3rdparty/libjpeg/qt_attribution.json | 2 +- src/3rdparty/libjpeg/src/ChangeLog.md | 44 ++++++++++++++++++++++++ src/3rdparty/libjpeg/src/jcdctmgr.c | 2 +- src/3rdparty/libjpeg/src/jdapistd.c | 33 +++++++++++++++--- src/3rdparty/libjpeg/src/jdcolor.c | 2 +- src/3rdparty/libjpeg/src/jdmerge.c | 2 +- 6 files changed, 76 insertions(+), 9 deletions(-) diff --git a/src/3rdparty/libjpeg/qt_attribution.json b/src/3rdparty/libjpeg/qt_attribution.json index a1966d43d62..9bfc14f29d8 100644 --- a/src/3rdparty/libjpeg/qt_attribution.json +++ b/src/3rdparty/libjpeg/qt_attribution.json @@ -6,7 +6,7 @@ "Description": "The Independent JPEG Group's JPEG software", "Homepage": "http://libjpeg-turbo.virtualgl.org/", - "Version": "1.5.2", + "Version": "1.5.3", "License": "Independent JPEG Group License", "LicenseId": "IJG", "LicenseFile": "LICENSE", diff --git a/src/3rdparty/libjpeg/src/ChangeLog.md b/src/3rdparty/libjpeg/src/ChangeLog.md index 2aaa50c1484..f5fe44bf851 100644 --- a/src/3rdparty/libjpeg/src/ChangeLog.md +++ b/src/3rdparty/libjpeg/src/ChangeLog.md @@ -1,3 +1,47 @@ +1.5.3 +===== + +### Significant changes relative to 1.5.2: + +1. Fixed a NullPointerException in the TurboJPEG Java wrapper that occurred +when using the YUVImage constructor that creates an instance backed by separate +image planes and allocates memory for the image planes. + +2. Fixed an issue whereby the Java version of TJUnitTest would fail when +testing BufferedImage encoding/decoding on big endian systems. + +3. Fixed a segfault in djpeg that would occur if an output format other than +PPM/PGM was selected along with the `-crop` option. The `-crop` option now +works with the GIF and Targa formats as well (unfortunately, it cannot be made +to work with the BMP and RLE formats due to the fact that those output engines +write scanlines in bottom-up order.) djpeg will now exit gracefully if an +output format other than PPM/PGM, GIF, or Targa is selected along with the +`-crop` option. + +4. Fixed an issue whereby `jpeg_skip_scanlines()` would segfault if color +quantization was enabled. + +5. TJBench (both C and Java versions) will now display usage information if any +command-line argument is unrecognized. This prevents the program from silently +ignoring typos. + +6. Fixed an access violation in tjbench.exe (Windows) that occurred when the +program was used to decompress an existing JPEG image. + +7. Fixed an ArrayIndexOutOfBoundsException in the TJExample Java program that +occurred when attempting to decompress a JPEG image that had been compressed +with 4:1:1 chrominance subsampling. + +8. Fixed an issue whereby, when using `jpeg_skip_scanlines()` to skip to the +end of a single-scan (non-progressive) image, subsequent calls to +`jpeg_consume_input()` would return `JPEG_SUSPENDED` rather than +`JPEG_REACHED_EOI`. + +9. `jpeg_crop_scanlines()` now works correctly when decompressing grayscale +JPEG images that were compressed with a sampling factor other than 1 (for +instance, with `cjpeg -grayscale -sample 2x2`). + + 1.5.2 ===== diff --git a/src/3rdparty/libjpeg/src/jcdctmgr.c b/src/3rdparty/libjpeg/src/jcdctmgr.c index aef8517f9c5..6e3b19bcb37 100644 --- a/src/3rdparty/libjpeg/src/jcdctmgr.c +++ b/src/3rdparty/libjpeg/src/jcdctmgr.c @@ -216,7 +216,7 @@ compute_reciprocal (UINT16 divisor, DCTELEM *dtbl) #endif dtbl[DCTSIZE2 * 3] = (DCTELEM) r - sizeof(DCTELEM)*8; /* shift */ - if(r <= 16) return 0; + if (r <= 16) return 0; else return 1; } diff --git a/src/3rdparty/libjpeg/src/jdapistd.c b/src/3rdparty/libjpeg/src/jdapistd.c index 37afc8448b9..105121df2be 100644 --- a/src/3rdparty/libjpeg/src/jdapistd.c +++ b/src/3rdparty/libjpeg/src/jdapistd.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1996, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2015-2016, D. R. Commander. + * Copyright (C) 2010, 2015-2017, D. R. Commander. * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README.ijg * file. @@ -190,7 +190,10 @@ jpeg_crop_scanline (j_decompress_ptr cinfo, JDIMENSION *xoffset, * single-pass decompression case, allowing us to use the same MCU column * width for all of the components. */ - align = cinfo->_min_DCT_scaled_size * cinfo->max_h_samp_factor; + if (cinfo->comps_in_scan == 1 && cinfo->num_components == 1) + align = cinfo->_min_DCT_scaled_size; + else + align = cinfo->_min_DCT_scaled_size * cinfo->max_h_samp_factor; /* Adjust xoffset to the nearest iMCU boundary <= the requested value */ input_xoffset = *xoffset; @@ -215,6 +218,9 @@ jpeg_crop_scanline (j_decompress_ptr cinfo, JDIMENSION *xoffset, for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; ci++, compptr++) { + int hsf = (cinfo->comps_in_scan == 1 && cinfo->num_components == 1) ? + 1 : compptr->h_samp_factor; + /* Set downsampled_width to the new output width. */ orig_downsampled_width = compptr->downsampled_width; compptr->downsampled_width = @@ -228,11 +234,10 @@ jpeg_crop_scanline (j_decompress_ptr cinfo, JDIMENSION *xoffset, * values will be used in multi-scan decompressions. */ cinfo->master->first_MCU_col[ci] = - (JDIMENSION) (long) (*xoffset * compptr->h_samp_factor) / - (long) align; + (JDIMENSION) (long) (*xoffset * hsf) / (long) align; cinfo->master->last_MCU_col[ci] = (JDIMENSION) jdiv_round_up((long) ((*xoffset + cinfo->output_width) * - compptr->h_samp_factor), + hsf), (long) align) - 1; } @@ -293,6 +298,14 @@ noop_convert (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, } +/* Dummy quantize function used by jpeg_skip_scanlines() */ +LOCAL(void) +noop_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) +{ +} + + /* * In some cases, it is best to call jpeg_read_scanlines() and discard the * output, rather than skipping the scanlines, because this allows us to @@ -308,14 +321,22 @@ read_and_discard_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines) void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows); + void (*color_quantize) (j_decompress_ptr cinfo, JSAMPARRAY input_buf, + JSAMPARRAY output_buf, int num_rows) = NULL; color_convert = cinfo->cconvert->color_convert; cinfo->cconvert->color_convert = noop_convert; + if (cinfo->cquantize && cinfo->cquantize->color_quantize) { + color_quantize = cinfo->cquantize->color_quantize; + cinfo->cquantize->color_quantize = noop_quantize; + } for (n = 0; n < num_lines; n++) jpeg_read_scanlines(cinfo, NULL, 1); cinfo->cconvert->color_convert = color_convert; + if (color_quantize) + cinfo->cquantize->color_quantize = color_quantize; } @@ -370,6 +391,8 @@ jpeg_skip_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines) /* Do not skip past the bottom of the image. */ if (cinfo->output_scanline + num_lines >= cinfo->output_height) { cinfo->output_scanline = cinfo->output_height; + (*cinfo->inputctl->finish_input_pass) (cinfo); + cinfo->inputctl->eoi_reached = TRUE; return cinfo->output_height - cinfo->output_scanline; } diff --git a/src/3rdparty/libjpeg/src/jdcolor.c b/src/3rdparty/libjpeg/src/jdcolor.c index ab8fa24925e..05cbf4df1fa 100644 --- a/src/3rdparty/libjpeg/src/jdcolor.c +++ b/src/3rdparty/libjpeg/src/jdcolor.c @@ -616,7 +616,7 @@ static const JLONG dither_matrix[4] = { static INLINE boolean is_big_endian(void) { int test_value = 1; - if(*(char *)&test_value != 1) + if (*(char *)&test_value != 1) return TRUE; return FALSE; } diff --git a/src/3rdparty/libjpeg/src/jdmerge.c b/src/3rdparty/libjpeg/src/jdmerge.c index 6276dd0950f..ca6f16c2525 100644 --- a/src/3rdparty/libjpeg/src/jdmerge.c +++ b/src/3rdparty/libjpeg/src/jdmerge.c @@ -503,7 +503,7 @@ static const JLONG dither_matrix[4] = { static INLINE boolean is_big_endian(void) { int test_value = 1; - if(*(char *)&test_value != 1) + if (*(char *)&test_value != 1) return TRUE; return FALSE; } From ab1e50757454b5afda2f6dec52d2eb16a32d4798 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 19 Jan 2018 23:32:58 -0800 Subject: [PATCH 047/146] QVariant: convert QDateTime and QTime to string with milliseconds This way, it's lossless. Change-Id: I5e421e32396d44e4b39efffd150b744e40fff3a1 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Lars Knoll --- src/corelib/kernel/qvariant.cpp | 4 ++-- tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 29429b5e551..93736ae8072 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -440,10 +440,10 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *str = v_cast(d)->toString(Qt::ISODate); break; case QVariant::Time: - *str = v_cast(d)->toString(Qt::ISODate); + *str = v_cast(d)->toString(Qt::ISODateWithMs); break; case QVariant::DateTime: - *str = v_cast(d)->toString(Qt::ISODate); + *str = v_cast(d)->toString(Qt::ISODateWithMs); break; #endif case QVariant::Bool: diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 0d45159d09c..6ec90a66c85 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -1099,8 +1099,9 @@ void tst_QVariant::toString_data() QTest::newRow( "bool" ) << QVariant( true ) << QString( "true" ); QTest::newRow( "qdate" ) << QVariant( QDate( 2002, 1, 1 ) ) << QString( "2002-01-01" ); - QTest::newRow( "qtime" ) << QVariant( QTime( 12, 34, 56 ) ) << QString( "12:34:56" ); - QTest::newRow( "qdatetime" ) << QVariant( QDateTime( QDate( 2002, 1, 1 ), QTime( 12, 34, 56 ) ) ) << QString( "2002-01-01T12:34:56" ); + QTest::newRow( "qtime" ) << QVariant( QTime( 12, 34, 56 ) ) << QString( "12:34:56.000" ); + QTest::newRow( "qtime-with-ms" ) << QVariant( QTime( 12, 34, 56, 789 ) ) << QString( "12:34:56.789" ); + QTest::newRow( "qdatetime" ) << QVariant( QDateTime( QDate( 2002, 1, 1 ), QTime( 12, 34, 56, 789 ) ) ) << QString( "2002-01-01T12:34:56.789" ); QTest::newRow( "llong" ) << QVariant( (qlonglong)Q_INT64_C(123456789012) ) << QString( "123456789012" ); QTest::newRow("QJsonValue") << QVariant(QJsonValue(QString("hello"))) << QString("hello"); @@ -1151,6 +1152,7 @@ void tst_QVariant::toTime_data() QTest::newRow( "qtime" ) << QVariant( QTime( 12, 34, 56 ) ) << QTime( 12, 34, 56 ); QTest::newRow( "qdatetime" ) << QVariant( QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56 ) ) ) << QTime( 12, 34, 56 ); QTest::newRow( "qstring" ) << QVariant( QString( "12:34:56" ) ) << QTime( 12, 34, 56 ); + QTest::newRow( "qstring-with-ms" ) << QVariant( QString( "12:34:56.789" ) ) << QTime( 12, 34, 56, 789 ); } void tst_QVariant::toTime() @@ -1171,6 +1173,10 @@ void tst_QVariant::toDateTime_data() << QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56 ) ); QTest::newRow( "qdate" ) << QVariant( QDate( 2002, 10, 10 ) ) << QDateTime( QDate( 2002, 10, 10 ), QTime( 0, 0, 0 ) ); QTest::newRow( "qstring" ) << QVariant( QString( "2002-10-10T12:34:56" ) ) << QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56 ) ); + QTest::newRow( "qstring-utc" ) << QVariant( QString( "2002-10-10T12:34:56Z" ) ) + << QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56 ), Qt::UTC ); + QTest::newRow( "qstring-with-ms" ) << QVariant( QString( "2002-10-10T12:34:56.789" ) ) + << QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56, 789 ) ); } void tst_QVariant::toDateTime() From e5c02b2579f53b50120ba19b7d041818e915be28 Mon Sep 17 00:00:00 2001 From: Alexey Safronov Date: Sun, 21 Jan 2018 21:04:29 +0300 Subject: [PATCH 048/146] Doc: fix wrong link to the example snippet in QApplication class Change-Id: Ib9a1b107dd8d2cd4bf541c3edf19a602fde6356f Reviewed-by: Cristian Maureira-Fredes Reviewed-by: Martin Smith Reviewed-by: Paul Wicking --- src/widgets/kernel/qapplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 943aeaa2d9b..0a12d1f6cf3 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -2868,7 +2868,7 @@ void QApplication::setStartDragDistance(int l) and the current position (e.g. in the mouse move event) is \c currentPos, you can find out if a drag should be started with code like this: - \snippet code/src_gui_kernel_qapplication.cpp 6 + \snippet code/src_gui_kernel_qapplication.cpp 7 Qt uses this value internally, e.g. in QFileDialog. From 6dbf3576093858d981d8321b00f0b19faa7cf217 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Fri, 13 Oct 2017 16:27:13 +0200 Subject: [PATCH 049/146] Fix asserts and crashes in QWinEventNotifier activation loop The backwards iteration was done under the assumption that the only valid modification of the winEventNotifierList in a slot connected to activated() would be the removal of the notifier itself. This is wrong. Instead, iterate forwards, like before 85403d0a, and check the index against the current list size in every iteration. This ensures that we do not run out of bounds while the list is modified. Also, retry the activation loop if the list was modified by a slot connected to activated(). This ensures that all notifiers with signaled handles are activated. Task-number: QTBUG-65940 Change-Id: I25f305463b9234f391abc51fe0628d02f49b6931 Reviewed-by: Friedemann Kleint Reviewed-by: Oswald Buddenhagen --- src/corelib/kernel/qeventdispatcher_win.cpp | 23 ++++--- src/corelib/kernel/qeventdispatcher_win_p.h | 1 + .../tst_qwineventnotifier.cpp | 60 +++++++++++++++++++ 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index bbd442d5704..330870f2198 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -905,6 +905,7 @@ bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier) return true; d->winEventNotifierList.append(notifier); + d->winEventNotifierListModified = true; if (!d->winEventNotifierActivatedEvent) d->winEventNotifierActivatedEvent = CreateEvent(0, TRUE, FALSE, nullptr); @@ -928,6 +929,7 @@ void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier) if (i == -1) return; d->winEventNotifierList.takeAt(i); + d->winEventNotifierListModified = true; QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier); if (nd->waitHandle) nd->unregisterWaitObject(); @@ -938,16 +940,19 @@ void QEventDispatcherWin32::activateEventNotifiers() Q_D(QEventDispatcherWin32); ResetEvent(d->winEventNotifierActivatedEvent); - // Iterate backwards, because the notifier might remove itself on activate(). - for (int i = d->winEventNotifierList.count(); --i >= 0;) { - QWinEventNotifier *notifier = d->winEventNotifierList.at(i); - QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier); - if (nd->signaledCount.load() != 0) { - --nd->signaledCount; - nd->unregisterWaitObject(); - d->activateEventNotifier(notifier); + // Activate signaled notifiers. Our winEventNotifierList can be modified in activation slots. + do { + d->winEventNotifierListModified = false; + for (int i = 0; i < d->winEventNotifierList.count(); ++i) { + QWinEventNotifier *notifier = d->winEventNotifierList.at(i); + QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier); + if (nd->signaledCount.load() != 0) { + --nd->signaledCount; + nd->unregisterWaitObject(); + d->activateEventNotifier(notifier); + } } - } + } while (d->winEventNotifierListModified); // Re-register the remaining activated notifiers. for (int i = 0; i < d->winEventNotifierList.count(); ++i) { diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index 683c7f8f36a..a7ed8dda8aa 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -195,6 +195,7 @@ public: HANDLE winEventNotifierActivatedEvent; QList winEventNotifierList; + bool winEventNotifierListModified = false; void activateEventNotifier(QWinEventNotifier * wen); QList queuedUserInputEvents; diff --git a/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp b/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp index 64e78ec3c3a..76efa008f7c 100644 --- a/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp +++ b/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp @@ -29,8 +29,11 @@ #include #include #include +#include +#include #include +#include #include class tst_QWinEventNotifier : public QObject @@ -44,6 +47,8 @@ private slots: void simple_data(); void simple(); void manyNotifiers(); + void disableNotifiersInActivatedSlot_data(); + void disableNotifiersInActivatedSlot(); private: HANDLE simpleHEvent; @@ -119,6 +124,7 @@ public: HANDLE eventHandle() const { return notifier.handle(); } int numberOfTimesActivated() const { return activatedCount; } + void setEnabled(bool b) { notifier.setEnabled(b); } signals: void activated(); @@ -180,6 +186,60 @@ void tst_QWinEventNotifier::manyNotifiers() })); } +using Indices = QVector; + +void tst_QWinEventNotifier::disableNotifiersInActivatedSlot_data() +{ + QTest::addColumn("count"); + QTest::addColumn("notifiersToSignal"); + QTest::addColumn("notifiersToDisable"); + QTest::addColumn("deleteNotifiers"); + QTest::newRow("disable_signaled") << 3 << Indices{1} << Indices{1} << false; + QTest::newRow("disable_signaled2") << 3 << Indices{1, 2} << Indices{1} << false; + QTest::newRow("disable_before_signaled") << 3 << Indices{1} << Indices{0, 1} << false; + QTest::newRow("disable_after_signaled") << 3 << Indices{1} << Indices{1, 2} << false; + QTest::newRow("delete_signaled") << 3 << Indices{1} << Indices{1} << true; + QTest::newRow("delete_before_signaled1") << 3 << Indices{1} << Indices{0} << true; + QTest::newRow("delete_before_signaled2") << 3 << Indices{1} << Indices{0, 1} << true; + QTest::newRow("delete_before_signaled3") << 4 << Indices{3, 1} << Indices{0, 1} << true; + QTest::newRow("delete_after_signaled1") << 3 << Indices{1} << Indices{1, 2} << true; + QTest::newRow("delete_after_signaled2") << 4 << Indices{1, 3} << Indices{1, 2} << true; + QTest::newRow("delete_after_signaled3") << 5 << Indices{1} << Indices{1, 4} << true; +} + +void tst_QWinEventNotifier::disableNotifiersInActivatedSlot() +{ + QFETCH(int, count); + QFETCH(Indices, notifiersToSignal); + QFETCH(Indices, notifiersToDisable); + QFETCH(bool, deleteNotifiers); + + QVarLengthArray, 10> events(count); + for (int i = 0; i < count; ++i) + events[i].reset(new EventWithNotifier); + + auto isActivatedOrNull = [&events](int i) { + return !events.at(i) || events.at(i)->numberOfTimesActivated() > 0; + }; + + for (auto &e : events) { + connect(e.get(), &EventWithNotifier::activated, [&]() { + for (int i : notifiersToDisable) { + if (deleteNotifiers) + events[i].reset(); + else + events.at(i)->setEnabled(false); + } + if (std::all_of(notifiersToSignal.begin(), notifiersToSignal.end(), isActivatedOrNull)) + QTimer::singleShot(0, &QTestEventLoop::instance(), SLOT(exitLoop())); + }); + } + for (int i : notifiersToSignal) + SetEvent(events.at(i)->eventHandle()); + QTestEventLoop::instance().enterLoop(30); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + QTEST_MAIN(tst_QWinEventNotifier) #include "tst_qwineventnotifier.moc" From b0310ddd163847beabf7da66c2190d0b9b5e6afb Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 26 Jan 2018 09:46:24 +0100 Subject: [PATCH 050/146] hellogles3 example: Fix start-up crash when using dynamic GL Move the instantiation of QGuiApplication to the top since it is required by QOpenGLContext::openGLModuleType(). Task-number: QTBUG-55671 Change-Id: I506cee193fe2ba48400851588a8ef079848bc2f4 Reviewed-by: Laszlo Agocs --- examples/opengl/hellogles3/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/opengl/hellogles3/main.cpp b/examples/opengl/hellogles3/main.cpp index a6c63986280..29b3b9617ab 100644 --- a/examples/opengl/hellogles3/main.cpp +++ b/examples/opengl/hellogles3/main.cpp @@ -64,6 +64,8 @@ int main(int argc, char *argv[]) { + QGuiApplication app(argc, argv); + QSurfaceFormat fmt; fmt.setDepthBufferSize(24); @@ -79,8 +81,6 @@ int main(int argc, char *argv[]) QSurfaceFormat::setDefaultFormat(fmt); - QGuiApplication app(argc, argv); - GLWindow glWindow; glWindow.showMaximized(); From f5b1b10a1120ce5f9ffb43cc05fe4a0e39f43e36 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 24 Jan 2018 12:38:10 +0100 Subject: [PATCH 051/146] Android: Fix compilation with warnings-are-errors Variable was added in e2e874415e1f1c6a96915d9dc85dd31c61f73e24 but is not used anywhere. Change-Id: Iff1e7c20317bb489978eb77d24b8da12493d7e45 Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/androidjniclipboard.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/platforms/android/androidjniclipboard.cpp b/src/plugins/platforms/android/androidjniclipboard.cpp index 833996403cc..d1690353398 100644 --- a/src/plugins/platforms/android/androidjniclipboard.cpp +++ b/src/plugins/platforms/android/androidjniclipboard.cpp @@ -47,7 +47,6 @@ namespace QtAndroidClipboard { QAndroidPlatformClipboard *m_manager = nullptr; - static char const *const QtNativeClassName = "org/qtproject/qt5/android/QtNative"; static JNINativeMethod methods[] = { {"onClipboardDataChanged", "()V", (void *)onClipboardDataChanged} }; From 089969540f4877c778172ee0ccbd69960a179b43 Mon Sep 17 00:00:00 2001 From: Konstantin Tokarev Date: Fri, 26 Jan 2018 19:10:46 +0300 Subject: [PATCH 052/146] Remove traces of Growl in QSystemTrayIcon code and documentation Growl support was removed in Qt 5.8. Change-Id: I00a36cd955194ca8ceee52841a89ca579da01284 Reviewed-by: Jake Petroules --- src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 2 -- src/widgets/util/qsystemtrayicon.cpp | 7 +------ 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index e756f0aeb08..f4c968ab57d 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -72,8 +72,6 @@ ** ****************************************************************************/ -#define QT_MAC_SYSTEMTRAY_USE_GROWL - #include "qcocoasystemtrayicon.h" #ifndef QT_NO_SYSTEMTRAYICON diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp index f7d048edcd0..884bed2e687 100644 --- a/src/widgets/util/qsystemtrayicon.cpp +++ b/src/widgets/util/qsystemtrayicon.cpp @@ -107,9 +107,7 @@ static QIcon messageIcon2qIcon(QSystemTrayIcon::MessageIcon icon) \li All X11 desktop environments that implement the D-Bus \l{http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierItem} specification, including recent versions of KDE and Unity. - \li All supported versions of \macos. Note that the Growl - notification system must be installed for - QSystemTrayIcon::showMessage() to display messages on \macos prior to 10.8 (Mountain Lion). + \li All supported versions of \macos. \endlist To check whether a system tray is present on the user's desktop, @@ -399,9 +397,6 @@ bool QSystemTrayIcon::supportsMessages() On Windows, the \a millisecondsTimeoutHint is usually ignored by the system when the application has focus. - On \macos, the Growl notification system must be installed for this function to - display messages. - Has been turned into a slot in Qt 5.2. \sa show(), supportsMessages() From 940fd1734b097cbac681298f13193851bf2bf2b9 Mon Sep 17 00:00:00 2001 From: Alexander Shevchenko Date: Thu, 25 Jan 2018 14:09:46 +0200 Subject: [PATCH 053/146] unify windows mkspecs: move angle/vulkan includes 'win32-icc' toolchain: - remove duplicated angle/vulkan includes. 'win32-g++' toolchain: - place angle/vulkan includes before the unrelated compiler-related variable re-definitions, similarly to the 'win32-clang-msvc', 'win32-icc', and 'win32-msvc' mkspecs. Change-Id: Ie04bc9fb1d51ec0366b42713439f680e51214bbc Reviewed-by: Oliver Wolff Reviewed-by: Oswald Buddenhagen --- mkspecs/win32-g++/qmake.conf | 5 ++--- mkspecs/win32-icc/qmake.conf | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf index 0a1cd2dd5af..9f366e08b86 100644 --- a/mkspecs/win32-g++/qmake.conf +++ b/mkspecs/win32-g++/qmake.conf @@ -10,6 +10,8 @@ load(device_config) include(../common/gcc-base.conf) include(../common/g++-base.conf) +include(../common/angle.conf) +include(../common/windows-vulkan.conf) # modifications to gcc-base.conf and g++-base.conf @@ -84,7 +86,4 @@ QMAKE_STRIPFLAGS_LIB += --strip-unneeded QMAKE_OBJCOPY = $${CROSS_COMPILE}objcopy QMAKE_NM = $${CROSS_COMPILE}nm -P -include(../common/angle.conf) -include(../common/windows-vulkan.conf) - load(qt_config) diff --git a/mkspecs/win32-icc/qmake.conf b/mkspecs/win32-icc/qmake.conf index cc9c6e7363c..6acb07f8aa5 100644 --- a/mkspecs/win32-icc/qmake.conf +++ b/mkspecs/win32-icc/qmake.conf @@ -58,7 +58,4 @@ QMAKE_LFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG QMAKE_LIB = xilib /NOLOGO -include(../common/angle.conf) -include(../common/windows-vulkan.conf) - load(qt_config) From b1a58b20ae109fac2756101fea4dcd8ee0b96531 Mon Sep 17 00:00:00 2001 From: Igor Mironchik Date: Thu, 25 Jan 2018 15:43:40 +0300 Subject: [PATCH 054/146] Fix missing update of QTreeView on setTreePosition() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was missing update in setTreePosition() or better to say update was but in not that part of QTreeView that needed. Now QTreeView correctly updates and paints tree decoration in a new place on changing tree position. [ChangeLog][QtWidgets][QTreeView] Fixed missing update of QTreeView on changing tree position. Task-number: QTBUG-65980 Change-Id: Id79ab8fcb39d511245a551068640684dd2a10cb9 Reviewed-by: Thorbjørn Lund Martsum --- src/widgets/itemviews/qtreeview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index 4795d9f1b14..8d273050714 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -987,7 +987,7 @@ void QTreeView::setTreePosition(int index) { Q_D(QTreeView); d->treePosition = index; - update(); + d->viewport->update(); } /*! From 6b1ecb1904c3f7281d90e672971f23d54bb76600 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 13 Dec 2017 15:00:36 +0200 Subject: [PATCH 055/146] Android: Hide handler(s) if the cursor is not visible anymore On Android if the edit control is bigger than the remaining screen we resize it, this caused the handler(s) to remain outside the control. A better fix will be to ensure that the cursor/selection remains visible when the control is resized but I don't know if this is the desired behavior on all platforms. Task-number: QTBUG-62994 Task-number: QTBUG-58700 Change-Id: If43eb7bc1ecde426697694a8f26118e95fccb80c Reviewed-by: Paul Olav Tvete --- src/plugins/platforms/android/qandroidinputcontext.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index fe4c5be4cba..fb33ad6e210 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -438,6 +438,16 @@ QAndroidInputContext::QAndroidInputContext() QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QAndroidInputContext::updateSelectionHandles); + QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::anchorRectangleChanged, + this, &QAndroidInputContext::updateSelectionHandles); + QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::inputItemClipRectangleChanged, this, [this]{ + auto im = qGuiApp->inputMethod(); + if (!im->inputItemClipRectangle().contains(im->anchorRectangle()) || + !im->inputItemClipRectangle().contains(im->cursorRectangle())) { + m_cursorHandleShown = CursorHandleNotShown; + updateSelectionHandles(); + } + }); } QAndroidInputContext::~QAndroidInputContext() From 626b33dca1dc0d95e80bf139c197fbb13d740277 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 15 Dec 2017 10:52:10 +0200 Subject: [PATCH 056/146] Do not allow empty selections Allowing empty selections leads to strange behavior, it switches from selection handles to cursor handle. Change-Id: Ida69346e2a47b13c92cfd68a555d6b94422bb580 Reviewed-by: Paul Olav Tvete --- src/gui/kernel/qplatforminputcontext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/kernel/qplatforminputcontext.cpp b/src/gui/kernel/qplatforminputcontext.cpp index 3f59116e9af..9771e6ba11f 100644 --- a/src/gui/kernel/qplatforminputcontext.cpp +++ b/src/gui/kernel/qplatforminputcontext.cpp @@ -287,6 +287,8 @@ void QPlatformInputContext::setSelectionOnFocusObject(const QPointF &anchorPos, if (success) { int cursor = QInputMethod::queryFocusObject(Qt::ImCursorPosition, cursorPos * mapToLocal).toInt(&success); if (success) { + if (anchor == cursor && anchorPos != cursorPos) + return; QList imAttributes; imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant())); QInputMethodEvent event(QString(), imAttributes); From b1fb4f8261abe6372d446ee93846310191c070ce Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 15 Dec 2017 10:58:51 +0200 Subject: [PATCH 057/146] Move selection handles 1mm down This way the user will not cover with his finger the text with the cursor/selection. Set the tolerance to 0.5mm which is less then the width of the thinnest letters (e.g. i, I, l) Change-Id: Ia5d50bd3f4fe79c89d01b3d7f5e5c22e94e8158b Reviewed-by: Paul Olav Tvete --- .../qtproject/qt5/android/CursorHandle.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java b/src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java index e6814c202df..abeab12f372 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java @@ -51,6 +51,7 @@ import android.graphics.drawable.Drawable; import android.view.MotionEvent; import android.widget.PopupWindow; import android.app.Activity; +import android.util.TypedValue; import android.view.ViewTreeObserver; /* This view represents one of the handle (selection or cursor handle) */ @@ -58,8 +59,8 @@ class CursorView extends ImageView { private CursorHandle mHandle; // The coordinare which where clicked - private int m_offsetX; - private int m_offsetY; + private float m_offsetX; + private float m_offsetY; CursorView (Context context, CursorHandle handle) { super(context); @@ -76,20 +77,18 @@ class CursorView extends ImageView public boolean onTouchEvent(MotionEvent ev) { switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: { - m_offsetX = Math.round(ev.getRawX()); - m_offsetY = Math.round(ev.getRawY()); + m_offsetX = ev.getRawX(); + m_offsetY = ev.getRawY() + getHeight() / 2; break; } case MotionEvent.ACTION_MOVE: { - mHandle.updatePosition(Math.round(ev.getRawX()) - m_offsetX, - Math.round(ev.getRawY()) - m_offsetY); + mHandle.updatePosition(Math.round(ev.getRawX() - m_offsetX), + Math.round(ev.getRawY() - m_offsetY)); break; } case MotionEvent.ACTION_UP: - break; - case MotionEvent.ACTION_CANCEL: break; } @@ -113,6 +112,7 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener private int m_lastY; int tolerance; private boolean m_rtl; + int m_yShift; public CursorHandle(Activity activity, View layout, int id, int attr, boolean rtl) { m_activity = activity; @@ -121,7 +121,8 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener m_layout = layout; DisplayMetrics metrics = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); - tolerance = Math.round(2 * metrics.density); + m_yShift = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, metrics); + tolerance = Math.min(1, (int)(m_yShift / 2f)); m_lastX = m_lastY = -1 - tolerance; m_rtl = rtl; } @@ -158,7 +159,7 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener m_layout.getLocationOnScreen(location); int x2 = x + location[0]; - int y2 = y + location[1]; + int y2 = y + location[1] + m_yShift; if (m_id == QtNative.IdCursorHandle) { x2 -= m_cursorView.getWidth() / 2 ; @@ -187,6 +188,7 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener // The handle was dragged by a given relative position public void updatePosition(int x, int y) { + y -= m_yShift; if (Math.abs(m_lastX - x) > tolerance || Math.abs(m_lastY - y) > tolerance) { QtNative.handleLocationChanged(m_id, x + m_posX, y + m_posY); m_lastX = x; From 5f924134ff48bc89defe4d6c2ccabeaea6b4450d Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 15 Dec 2017 11:08:16 +0200 Subject: [PATCH 058/146] Check selection handles position This patch fixes the strange behavior when selecting text. This patch (on a Left To Right text) makes sure that: - the left handle will select text only on the left & above of the right handle - the right handle will select text only on the right & below of the left handle For RTL is way more complicated: - the left handle is acuatually the right handle but on the left side and it acts as a right handle - the right handle is acuatually the left handle but on the right side and it acts as a left handle Change-Id: Ifca591398103199d5aef479f0a080161c9f44c0e Reviewed-by: Paul Olav Tvete --- .../android/qandroidinputcontext.cpp | 48 ++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index fb33ad6e210..f548a1fa96f 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -605,27 +605,63 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y) double pixelDensity = window ? QHighDpiScaling::factor(window) : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); - QPoint point(x / pixelDensity, y / pixelDensity); - y -= leftRect.width() / 2; + QPointF point(x / pixelDensity, y / pixelDensity); + point.setY(point.y() - leftRect.width() / 2); if (handleId == 1) { setSelectionOnFocusObject(point, point); return; } - QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition); + QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImCurrentSelection); QCoreApplication::sendEvent(m_focusObject, &query); int cpos = query.value(Qt::ImCursorPosition).toInt(); int anchor = query.value(Qt::ImAnchorPosition).toInt(); - + bool rtl = query.value(Qt::ImCurrentSelection).toString().isRightToLeft(); auto rightRect = im->anchorRectangle(); if (cpos > anchor) std::swap(leftRect, rightRect); + auto checkLeftHandle = [&rightRect](QPointF &handlePos) { + if (handlePos.y() > rightRect.center().y()) + handlePos.setY(rightRect.center().y()); // adjust Y handle pos + if (handlePos.y() >= rightRect.y() && handlePos.y() <= rightRect.bottom() && handlePos.x() >= rightRect.x()) + return false; // same line and wrong X pos ? + return true; + }; + + auto checkRtlRightHandle = [&rightRect](QPointF &handlePos) { + if (handlePos.y() > rightRect.center().y()) + handlePos.setY(rightRect.center().y()); // adjust Y handle pos + if (handlePos.y() >= rightRect.y() && handlePos.y() <= rightRect.bottom() && rightRect.x() >= handlePos.x()) + return false; // same line and wrong X pos ? + return true; + }; + + auto checkRightHandle = [&leftRect](QPointF &handlePos) { + if (handlePos.y() < leftRect.center().y()) + handlePos.setY(leftRect.center().y()); // adjust Y handle pos + if (handlePos.y() >= leftRect.y() && handlePos.y() <= leftRect.bottom() && leftRect.x() >= handlePos.x()) + return false; // same line and wrong X pos ? + return true; + }; + + auto checkRtlLeftHandle = [&leftRect](QPointF &handlePos) { + if (handlePos.y() < leftRect.center().y()) + handlePos.setY(leftRect.center().y()); // adjust Y handle pos + if (handlePos.y() >= leftRect.y() && handlePos.y() <= leftRect.bottom() && handlePos.x() >= leftRect.x()) + return false; // same line and wrong X pos ? + return true; + }; + if (handleId == 2) { - QPoint rightPoint(rightRect.center().toPoint()); + QPointF rightPoint(rightRect.center()); + if ((!rtl && !checkLeftHandle(point)) || (rtl && !checkRtlRightHandle(point))) + return; setSelectionOnFocusObject(point, rightPoint); } else if (handleId == 3) { - QPoint leftPoint(leftRect.center().toPoint()); + QPointF leftPoint(leftRect.center()); + if ((!rtl && !checkRightHandle(point)) || (rtl && !checkRtlLeftHandle(point))) + return; setSelectionOnFocusObject(leftPoint, point); } } From f3397ec659bc1288bebcb0dec11cc48cdd2c17bb Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 15 Dec 2017 14:30:14 +0200 Subject: [PATCH 059/146] Don't update the position if the handle was not first pressed Change-Id: If09a2ca954a3bfca00b5a0839fea2899e7576c1d Reviewed-by: Paul Olav Tvete --- .../jar/src/org/qtproject/qt5/android/CursorHandle.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java b/src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java index abeab12f372..4f2c06644d4 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java @@ -61,6 +61,7 @@ class CursorView extends ImageView // The coordinare which where clicked private float m_offsetX; private float m_offsetY; + private boolean m_pressed = false; CursorView (Context context, CursorHandle handle) { super(context); @@ -79,10 +80,13 @@ class CursorView extends ImageView case MotionEvent.ACTION_DOWN: { m_offsetX = ev.getRawX(); m_offsetY = ev.getRawY() + getHeight() / 2; + m_pressed = true; break; } case MotionEvent.ACTION_MOVE: { + if (!m_pressed) + return false; mHandle.updatePosition(Math.round(ev.getRawX() - m_offsetX), Math.round(ev.getRawY() - m_offsetY)); break; @@ -90,6 +94,7 @@ class CursorView extends ImageView case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: + m_pressed = false; break; } return true; From 5a05348fb6c3940449a9c2950bb65bdea2112a15 Mon Sep 17 00:00:00 2001 From: Frank Richter Date: Tue, 23 Jan 2018 14:06:53 +0100 Subject: [PATCH 060/146] examples: Add localserver feature check for localfortune examples Change-Id: I536645ddf0a5ead31a2658d03984c1226a7c39c8 Reviewed-by: Oswald Buddenhagen --- examples/corelib/ipc/ipc.pro | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/corelib/ipc/ipc.pro b/examples/corelib/ipc/ipc.pro index 101552cea96..68c88d75aad 100644 --- a/examples/corelib/ipc/ipc.pro +++ b/examples/corelib/ipc/ipc.pro @@ -3,4 +3,8 @@ requires(qtHaveModule(widgets)) TEMPLATE = subdirs qtConfig(sharedmemory): SUBDIRS = sharedmemory -qtHaveModule(network): SUBDIRS += localfortuneserver localfortuneclient +qtHaveModule(network) { + QT_FOR_CONFIG += network + + qtConfig(localserver): SUBDIRS += localfortuneserver localfortuneclient +} From 3adfcbf1ed9b63c3ce41d7417658db3836fd3530 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 21 Jan 2018 19:55:40 +0100 Subject: [PATCH 061/146] QHeaderView: properly restore section data after layoutChanged() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QHeaderView is doing a complete rebuild of the sections when the layout changed because everything could have happened. But since layoutChanged is also called during e.g. sorting, the old data must be restored when possible. Task-number: QTBUG-65478 Change-Id: I088d4d843cad362b97df6dc5e0dcb9819b13547f Reviewed-by: Thorbjørn Lund Martsum Reviewed-by: Richard Moe Gustavsen --- src/widgets/itemviews/qheaderview.cpp | 88 ++++++++++++++----- src/widgets/itemviews/qheaderview_p.h | 11 +-- .../itemviews/qheaderview/tst_qheaderview.cpp | 13 ++- 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 0905a208124..e1aec3f4bd9 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -351,7 +351,7 @@ void QHeaderView::setModel(QAbstractItemModel *model) if (model == this->model()) return; Q_D(QHeaderView); - d->persistentHiddenSections.clear(); + d->layoutChangePersistentSections.clear(); if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) { if (d->orientation == Qt::Horizontal) { QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)), @@ -2072,14 +2072,28 @@ void QHeaderViewPrivate::_q_layoutAboutToBeChanged() || model->columnCount(root) == 0) return; - if (hiddenSectionSize.count() == 0) - return; + layoutChangePersistentSections.clear(); + layoutChangePersistentSections.reserve(std::min(10, sectionItems.count())); + // after layoutChanged another section can be last stretched section + if (stretchLastSection) { + const int visual = visualIndex(lastSectionLogicalIdx); + sectionItems[visual].size = lastSectionSize; + } + for (int i = 0; i < sectionItems.size(); ++i) { + const auto &s = sectionItems.at(i); + // only add if the section is not default and not visually moved + if (s.size == defaultSectionSize && !s.isHidden && s.resizeMode == globalResizeMode) + continue; - for (int i = 0; i < sectionItems.count(); ++i) - if (isVisualIndexHidden(i)) // ### note that we are using column or row 0 - persistentHiddenSections.append(orientation == Qt::Horizontal - ? model->index(0, logicalIndex(i), root) - : model->index(logicalIndex(i), 0, root)); + // ### note that we are using column or row 0 + layoutChangePersistentSections.append({orientation == Qt::Horizontal + ? model->index(0, logicalIndex(i), root) + : model->index(logicalIndex(i), 0, root), + s}); + + if (layoutChangePersistentSections.size() > 1000) + break; + } } void QHeaderViewPrivate::_q_layoutChanged() @@ -2087,25 +2101,57 @@ void QHeaderViewPrivate::_q_layoutChanged() Q_Q(QHeaderView); viewport->update(); - const auto hiddenSections = persistentHiddenSections; - persistentHiddenSections.clear(); + const auto oldPersistentSections = layoutChangePersistentSections; + layoutChangePersistentSections.clear(); - clear(); - q->initializeSections(); - invalidateCachedSizeHint(); - - if (modelIsEmpty()) { + const int newCount = modelSectionCount(); + const int oldCount = sectionItems.size(); + if (newCount == 0) { + clear(); + if (oldCount != 0) + emit q->sectionCountChanged(oldCount, 0); return; } - for (const auto &index : hiddenSections) { - if (index.isValid()) { - const int logical = (orientation == Qt::Horizontal - ? index.column() - : index.row()); - q->setSectionHidden(logical, true); + // adjust section size + if (newCount != oldCount) { + const int min = qBound(0, oldCount, newCount - 1); + q->initializeSections(min, newCount - 1); + } + // reset sections + sectionItems.fill(SectionItem(defaultSectionSize, globalResizeMode), newCount); + + // all hidden sections are in oldPersistentSections + hiddenSectionSize.clear(); + + for (const auto &item : oldPersistentSections) { + const auto &index = item.index; + if (!index.isValid()) + continue; + + const int newLogicalIndex = (orientation == Qt::Horizontal + ? index.column() + : index.row()); + // the new visualIndices are already adjusted / reset by initializeSections() + const int newVisualIndex = visualIndex(newLogicalIndex); + auto &newSection = sectionItems[newVisualIndex]; + newSection = item.section; + + if (newSection.isHidden) { + // otherwise setSectionHidden will return without doing anything + newSection.isHidden = false; + q->setSectionHidden(newLogicalIndex, true); } } + + recalcSectionStartPos(); + length = headerLength(); + + if (stretchLastSection) { + // force rebuild of stretched section later on + lastSectionLogicalIdx = -1; + maybeRestorePrevLastSectionAndStretchLast(); + } } /*! diff --git a/src/widgets/itemviews/qheaderview_p.h b/src/widgets/itemviews/qheaderview_p.h index 8fc8b88aa5d..c9c2cf84938 100644 --- a/src/widgets/itemviews/qheaderview_p.h +++ b/src/widgets/itemviews/qheaderview_p.h @@ -231,10 +231,6 @@ public: : model->rowCount(root)); } - inline bool modelIsEmpty() const { - return (model->rowCount(root) == 0 || model->columnCount(root) == 0); - } - inline void doDelayedResizeSections() { if (!delayedResize.isActive()) delayedResize.start(0, q_func()); @@ -304,7 +300,6 @@ public: QLabel *sectionIndicator; #endif QHeaderView::ResizeMode globalResizeMode; - QList persistentHiddenSections; mutable bool sectionStartposRecalc; int resizeContentsPrecision; // header sections @@ -335,6 +330,11 @@ public: }; QVector sectionItems; + struct LayoutChangeItem { + QPersistentModelIndex index; + SectionItem section; + }; + QVector layoutChangePersistentSections; void createSectionItems(int start, int end, int size, QHeaderView::ResizeMode mode); void removeSectionsFromSectionItems(int start, int end); @@ -388,6 +388,7 @@ public: }; Q_DECLARE_TYPEINFO(QHeaderViewPrivate::SectionItem, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QHeaderViewPrivate::LayoutChangeItem, Q_MOVABLE_TYPE); QT_END_NAMESPACE diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index 90019a17981..6dae2cf8e47 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -2251,10 +2251,6 @@ void tst_QHeaderView::QTBUG6058_reset() void tst_QHeaderView::QTBUG7833_sectionClicked() { - - - - QTableView tv; QStandardItemModel *sim = new QStandardItemModel(&tv); QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(&tv); @@ -2278,11 +2274,20 @@ void tst_QHeaderView::QTBUG7833_sectionClicked() tv.horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); tv.setModel(proxyModel); + const int section4Size = tv.horizontalHeader()->sectionSize(4) + 1; + tv.horizontalHeader()->resizeSection(4, section4Size); tv.setColumnHidden(5, true); tv.setColumnHidden(6, true); tv.horizontalHeader()->swapSections(8, 10); tv.sortByColumn(1, Qt::AscendingOrder); + QCOMPARE(tv.isColumnHidden(5), true); + QCOMPARE(tv.isColumnHidden(6), true); + QCOMPARE(tv.horizontalHeader()->sectionsMoved(), true); + QCOMPARE(tv.horizontalHeader()->logicalIndex(8), 10); + QCOMPARE(tv.horizontalHeader()->logicalIndex(10), 8); + QCOMPARE(tv.horizontalHeader()->sectionSize(4), section4Size); + QSignalSpy clickedSpy(tv.horizontalHeader(), SIGNAL(sectionClicked(int))); QSignalSpy pressedSpy(tv.horizontalHeader(), SIGNAL(sectionPressed(int))); From 11f6c646967c61e3eac6302a2d4ea8f30a41beff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 24 Jan 2018 12:35:29 +0100 Subject: [PATCH 062/146] rasterwindow: End painting on device before ending on backingstore Change-Id: Ib42de1d7ad0d14e2e2d2ff75606e6cfd7e584c2a Reviewed-by: Simon Hausmann --- examples/gui/rasterwindow/rasterwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/gui/rasterwindow/rasterwindow.cpp b/examples/gui/rasterwindow/rasterwindow.cpp index 68d1d7f524b..3eacd201455 100644 --- a/examples/gui/rasterwindow/rasterwindow.cpp +++ b/examples/gui/rasterwindow/rasterwindow.cpp @@ -111,6 +111,7 @@ void RasterWindow::renderNow() painter.fillRect(0, 0, width(), height(), Qt::white); render(&painter); + painter.end(); m_backingStore->endPaint(); m_backingStore->flush(rect); From 4a7771f206d4b29be549d3827c36a46679d90de6 Mon Sep 17 00:00:00 2001 From: Eike Hein Date: Sun, 7 Jan 2018 13:02:01 +0900 Subject: [PATCH 063/146] QSimpleDrag: Fix mouse release coords for delayed event transmission On platforms such as XCB, the drag cursor pixmap is shown via a window (a QShapedPixmapWindow) under the cursor. The mouse button release event at the end of the drag is received in this QXcbWindow, but intercepted by an event filter that QSimpleDrag installs on the QApplication. It then resends it unmodified(!) after the drag has ended and the drag pixmap window destroyed, causing it to be delivered to the new top-level window. The local coordinates in the unmodified QMouseEvent are local to the drag pixmap window and don't match the window it is delayed-transmitted to. This ends up having fatal, user-visible effects particularly in Qt Quick: QQuickWindow synthesizes a hover event once per frame using the last received mouse coordinates, here: the release posted by QSimpleDrag. This is done to update the hover event state for items under the cursor when the mouse hasn't moved (e.g. QQuickMouseArea:: containsMouse). The bogus event coordinates in the release event then usually end up causing an item near the top-left of the QQuickWindow to assume it is hovered (because drag pixmap windows tend to be small), even when the mouse cursor is actually far away from it at the end of the drag. This shows up e.g. in the Plasma 5 desktop, where dragging an icon on the desktop will cause the icon at the top-left of the screen (if any) to switch to hovered state, as the release coordinates on the drag pixmap window (showing a dragged icon) fall into the geometry of the top-left icon. QSimpleDrag contains a topLevelAt() function to find the top-level window under the global cursor coordinates that is not the drag pixmap window. This is used by the drop event delivery code. This patch uses this function to find the relevant top-level window, then asks it to map the global cusor coordinates to its local coordinate system, then synthesizes a new QMouseEvent with local coordinates computed in this fashion. As a result the window now gets a release event with coordinates that make sense and are correct. Task-number: QTBUG-66103 Change-Id: I04ebe6ccd4a991fdd4b540ff0227973ea8896a9d Reviewed-by: Eike Hein Reviewed-by: Shawn Rutledge --- src/gui/kernel/qsimpledrag.cpp | 32 +++++++++++++++++++++++++++----- src/gui/kernel/qsimpledrag_p.h | 6 +++--- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index a1e25dc53c0..87d3ba5915b 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -58,6 +58,7 @@ #include #include +#include #include #include @@ -69,6 +70,8 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_DRAGANDDROP +Q_LOGGING_CATEGORY(lcDnd, "qt.gui.dnd") + static QWindow* topLevelAt(const QPoint &pos) { QWindowList list = QGuiApplication::topLevelWindows(); @@ -94,10 +97,10 @@ static QWindow* topLevelAt(const QPoint &pos) */ QBasicDrag::QBasicDrag() : - m_restoreCursor(false), m_eventLoop(0), + m_current_window(nullptr), m_restoreCursor(false), m_eventLoop(nullptr), m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false), - m_drag(0), m_drag_icon_window(0), m_useCompositing(true), - m_screen(Q_NULLPTR) + m_drag(nullptr), m_drag_icon_window(nullptr), m_useCompositing(true), + m_screen(nullptr) { } @@ -161,6 +164,7 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e) return true; // Eat all mouse move events } case QEvent::MouseButtonRelease: + { disableEventFilter(); if (canDrop()) { QPoint nativePosition = getNativeMousePos(e, m_drag_icon_window); @@ -169,8 +173,25 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e) cancel(); } exitDndEventLoop(); - QCoreApplication::postEvent(o, new QMouseEvent(*static_cast(e))); + + // If a QShapedPixmapWindow (drag feedback) is being dragged along, the + // mouse event's localPos() will be relative to that, which is useless. + // We want a position relative to the window where the drag ends, if possible (?). + // If there is no such window (belonging to this Qt application), + // make the event relative to the window where the drag started. (QTBUG-66103) + const QMouseEvent *release = static_cast(e); + const QWindow *releaseWindow = topLevelAt(release->globalPos()); + qCDebug(lcDnd) << "mouse released over" << releaseWindow << "after drag from" << m_current_window << "globalPos" << release->globalPos(); + if (!releaseWindow) + releaseWindow = m_current_window; + QPoint releaseWindowPos = (releaseWindow ? releaseWindow->mapFromGlobal(release->globalPos()) : release->globalPos()); + QMouseEvent *newRelease = new QMouseEvent(release->type(), + releaseWindowPos, releaseWindowPos, release->screenPos(), + release->button(), release->buttons(), + release->modifiers(), release->source()); + QCoreApplication::postEvent(o, newRelease); return true; // defer mouse release events until drag event loop has returned + } case QEvent::MouseButtonDblClick: case QEvent::Wheel: return true; @@ -349,7 +370,7 @@ static inline QPoint fromNativeGlobalPixels(const QPoint &point) into account. */ -QSimpleDrag::QSimpleDrag() : m_current_window(0) +QSimpleDrag::QSimpleDrag() { } @@ -373,6 +394,7 @@ void QSimpleDrag::startDrag() updateCursor(Qt::IgnoreAction); } setExecutedDropAction(Qt::IgnoreAction); + qCDebug(lcDnd) << "drag began from" << m_current_window<< "cursor pos" << QCursor::pos() << "can drop?" << canDrop(); } void QSimpleDrag::cancel() diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h index 0b8a0bc7030..bbd7f7f4bbb 100644 --- a/src/gui/kernel/qsimpledrag_p.h +++ b/src/gui/kernel/qsimpledrag_p.h @@ -105,6 +105,9 @@ protected: QDrag *drag() const { return m_drag; } +protected: + QWindow *m_current_window; + private: void enableEventFilter(); void disableEventFilter(); @@ -132,9 +135,6 @@ protected: virtual void cancel() Q_DECL_OVERRIDE; virtual void move(const QPoint &globalPos) Q_DECL_OVERRIDE; virtual void drop(const QPoint &globalPos) Q_DECL_OVERRIDE; - -private: - QWindow *m_current_window; }; #endif // QT_NO_DRAGANDDROP From 4cd90a3579986ae7441c3e982a5f34cdfd92c152 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 17 Jan 2017 22:31:04 +0000 Subject: [PATCH 064/146] Fix native QFileDialog initial selection for remote URLs When using QFileDialog::getOpenFileUrl() with dir set to e.g. "sftp://foo/bar.cpp" we call q->selectDirectoryUrl("sftp://foo") followed by q->selectFile("bar.cpp"). Inside QFileDialog::selectFile() we unconditionally convert "bar.cpp" to an absolute URL and then call d->selectFile_sys("$CWD/bar.cpp") This then calls platform integration that detects that an absolute URL is being passed to selectFile() and therefore overrides the initial directory. Initially reported as https://bugs.kde.org/show_bug.cgi?id=374913 This is a regression that appeared some time between Qt 5.7.0 and 5.7.1. I have not had time to bisect this but the only commit that may have change behavior in that time range appears to be 007f92c6eef6191c48da0c44916591d48813ae62. Change-Id: I6968abe9ed5c5b9de067c453a7e9d2c5cdb3a190 Reviewed-by: Christoph Resch Reviewed-by: David Faure --- src/widgets/dialogs/qfiledialog.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 8d37969be49..cb2c534b246 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -2830,7 +2830,10 @@ void QFileDialogPrivate::init(const QUrl &directory, const QString &nameFilter, if (!nameFilter.isEmpty()) q->setNameFilter(nameFilter); q->setDirectoryUrl(workingDirectory(directory)); - q->selectFile(initialSelection(directory)); + if (directory.isLocalFile()) + q->selectFile(initialSelection(directory)); + else + q->selectUrl(directory); #ifndef QT_NO_SETTINGS // Try to restore from the FileDialog settings group; if it fails, fall back From 7d1962cada48f8c351909d1ccc14b13c3adaa542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 22 Jan 2018 17:28:10 +0100 Subject: [PATCH 065/146] macOS: Handle update requests via setNeedsDisplay more carefully Instead of trying to detect situations where we need to send a real expose event instead of an update request in response to a drawRect call, we keep track of when we've asked the view to display due to a requestUpdate call, and only deliver the corresponding drawRect as an update request if no other code has asked the view to display. This should cover all cases of asking the view to display, issued from our code or from AppKit, such as the view changing its backing scale factor, or otherwise needing a real expose event. Task-number: QTBUG-65663 Change-Id: I1783787823aee889dad8e48f34a1cb0f1b7b06bd Reviewed-by: Shawn Rutledge --- src/plugins/platforms/cocoa/qcocoawindow.mm | 19 +-------- src/plugins/platforms/cocoa/qnsview.h | 3 ++ src/plugins/platforms/cocoa/qnsview.mm | 44 ++++++++++++++++----- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 92df6eac498..af2931c747e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1157,23 +1157,6 @@ void QCocoaWindow::handleExposeEvent(const QRegion ®ion) m_exposedRect = QRect(); } - QWindowPrivate *windowPrivate = qt_window_private(window()); - if (windowPrivate->updateRequestPending) { - // We can only deliver update request events when the window is exposed, - // and we also have to make sure we deliver any change to the exposed - // rect as a real expose event (including going from non-exposed to - // exposed). FIXME: Should this logic live in QGuiApplication? - if (isExposed() && m_exposedRect == previouslyExposedRect) { - qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "as update request"; - windowPrivate->deliverUpdateRequest(); - return; - } else { - // Since updateRequestPending is still set, we will issue a deferred setNeedsDisplay - // from drawRect and get back into this code on the next display cycle, delivering - // the pending update request. - } - } - qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed(); QWindowSystemInterface::handleExposeEvent(window(), region); } @@ -1348,7 +1331,7 @@ void QCocoaWindow::recreateWindowIfNeeded() void QCocoaWindow::requestUpdate() { qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::requestUpdate" << window(); - [m_view setNeedsDisplay:YES]; + [m_view requestUpdate]; } void QCocoaWindow::requestActivateWindow() diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index f8903725a65..e2ea862cd5b 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -81,6 +81,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); NSEvent *m_currentlyInterpretedKeyEvent; bool m_isMenuView; QSet m_acceptedKeyDowns; + bool m_updateRequested; } @property (nonatomic, retain) NSCursor *cursor; @@ -105,6 +106,8 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); - (void)resetMouseButtons; +- (void)requestUpdate; + - (void)handleMouseEvent:(NSEvent *)theEvent; - (bool)handleMouseDownEvent:(NSEvent *)theEvent withButton:(int)buttonNumber; - (bool)handleMouseDraggedEvent:(NSEvent *)theEvent withButton:(int)buttonNumber; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 61f0012a2d6..e3bee95ad9a 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -147,6 +147,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") m_isMenuView = false; self.focusRingType = NSFocusRingTypeNone; self.cursor = nil; + m_updateRequested = false; } return self; } @@ -299,6 +300,25 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") return m_platformWindow->isOpaque(); } +- (void)requestUpdate +{ + if (self.needsDisplay) { + // If the view already has needsDisplay set it means that there may be code waiting for + // a real expose event, so we can't issue setNeedsDisplay now as a way to trigger an + // update request. We will re-trigger requestUpdate from drawRect. + return; + } + + [self setNeedsDisplay:YES]; + m_updateRequested = true; +} + +- (void)setNeedsDisplayInRect:(NSRect)rect +{ + [super setNeedsDisplayInRect:rect]; + m_updateRequested = false; +} + - (void)drawRect:(NSRect)dirtyRect { Q_UNUSED(dirtyRect); @@ -322,18 +342,24 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") } #endif - m_platformWindow->handleExposeEvent(exposedRegion); + QWindowPrivate *windowPrivate = qt_window_private(m_platformWindow->window()); - if (qt_window_private(m_platformWindow->window())->updateRequestPending) { - // A call to QWindow::requestUpdate was issued during the expose event, or we - // had to deliver a real expose event and still need to deliver the update. - // But AppKit will reset the needsDisplay state of the view after completing + if (m_updateRequested) { + Q_ASSERT(windowPrivate->updateRequestPending); + qCDebug(lcQpaCocoaWindow) << "Delivering update request to" << m_platformWindow->window(); + windowPrivate->deliverUpdateRequest(); + m_updateRequested = false; + } else { + m_platformWindow->handleExposeEvent(exposedRegion); + } + + if (windowPrivate->updateRequestPending) { + // A call to QWindow::requestUpdate was issued during event delivery above, + // but AppKit will reset the needsDisplay state of the view after completing // the current display cycle, so we need to defer the request to redisplay. // FIXME: Perhaps this should be a trigger to enable CADisplayLink? - qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:] issuing deferred setNeedsDisplay due to pending update request"; - dispatch_async(dispatch_get_main_queue (), ^{ - [self setNeedsDisplay:YES]; - }); + qCDebug(lcQpaCocoaWindow) << "Pending update request, triggering re-display"; + dispatch_async(dispatch_get_main_queue (), ^{ [self requestUpdate]; }); } } From 538b1b50764fb3a1898d425a7155319afbcf3b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 1 Feb 2018 12:17:48 +0100 Subject: [PATCH 066/146] Android: Defer initialization of logging rules until qApp construction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Android, we load the application library, and its dependencies (Qt), on Android's main thread (thread 0), and then spin up a secondary thread (thread 1), that we call main() on. If any QObject is constructed during loading of the application library or any of Qt's libraries, via static initializers or constructor functions, we will set QCoreApplicationPrivate::theMainThread to thread 0, which will confuse Qt later on when it's being run on thread 1, and will result in a warning during QCoreApplication construction: QApplication was not created in the main() thread This situation can easily lead to a crash as well. Unfortunately logging via qDebug/qCDebug and friends will trigger this too, as they internally use QObject. Fixing the root cause of this is under investigation, but for now we will partially revert fa2a653b3b934783 for Android. The effect is that any qCDebug with a "qt.*" category before qApp construction will turn into a no-op, like it was before fa2a653b3b934783. This patch does not cover the case of a regular qDebug, or a qCDebug with a non-Qt category. Those will still produce the same symptom, as before fa2a653b3b934783. Task-number: QTBUG-65863 Change-Id: I95675731d233244530d0a2a1c82a9578d5599775 Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Tor Arne Vestbø --- src/corelib/io/qloggingregistry.cpp | 10 ++++++++++ src/corelib/kernel/qcoreapplication.cpp | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index b5f8e30b803..cd97268d716 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -44,6 +44,7 @@ #include #include #include +#include // We can't use the default macros because this would lead to recursion. // Instead let's define our own one that unconditionally logs... @@ -255,6 +256,15 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line) QLoggingRegistry::QLoggingRegistry() : categoryFilter(defaultCategoryFilter) { +#if defined(Q_OS_ANDROID) + // Unless QCoreApplication has been constructed we can't be sure that + // we are on Qt's main thread. If we did allow logging here, we would + // potentially set Qt's main thread to Android's thread 0, which would + // confuse Qt later when running main(). + if (!qApp) + return; +#endif + initializeRules(); // Init on first use } diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 9ec8262bf90..38148946304 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -802,6 +802,14 @@ void QCoreApplicationPrivate::init() if (!coreappdata()->applicationVersionSet) coreappdata()->applicationVersion = appVersion(); +#if defined(Q_OS_ANDROID) + // We've deferred initializing the logging registry due to not being + // able to guarantee that logging happened on the same thread as the + // Qt main thread, but now that the Qt main thread is set up, we can + // enable categorized logging. + QLoggingRegistry::instance()->initializeRules(); +#endif + #if QT_CONFIG(library) // Reset the lib paths, so that they will be recomputed, taking the availability of argv[0] // into account. If necessary, recompute right away and replay the manual changes on top of the From 9b2913377807b3dae107befeec0bc488f4a2cbad Mon Sep 17 00:00:00 2001 From: Nathan Collins Date: Mon, 29 Jan 2018 14:37:57 +0000 Subject: [PATCH 067/146] Fix QFileDialog::defaultSuffix on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't prepend the default suffix to the NSSavePanel allowedFileTypes. "If no extension is given by the user, the first item in the allowedFileTypes array will be used as the extension for the save panel." The user expects to get the suffix displayed to them in the drop down filter, not the default suffix set by the developer. Apply the default suffix if neither the user or the NSSavePanel provide a suffix. Task-number: QTBUG-66066 Change-Id: I64093b9f3178bd2377a7b65d6f23aed6214a4119 Reviewed-by: Morten Johan Sørvig --- .../platforms/cocoa/qcocoafiledialoghelper.mm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 74148b7cbf9..c1c79037662 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -418,6 +418,13 @@ static QString strippedText(QString s) } else { QList result; QString filename = QString::fromNSString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); + const QString defaultSuffix = mOptions->defaultSuffix(); + const QFileInfo fileInfo(filename); + // If neither the user or the NSSavePanel have provided a suffix, use + // the default suffix (if it exists). + if (fileInfo.suffix().isEmpty() && !defaultSuffix.isEmpty()) { + filename.append('.').append(defaultSuffix); + } result << QUrl::fromLocalFile(filename.remove(QLatin1String("___qt_very_unlikely_prefix_"))); return result; } @@ -445,10 +452,7 @@ static QString strippedText(QString s) [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead? if (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) { - QStringList ext = [self acceptableExtensionsForSave]; - const QString defaultSuffix = mOptions->defaultSuffix(); - if (!ext.isEmpty() && !defaultSuffix.isEmpty()) - ext.prepend(defaultSuffix); + const QStringList ext = [self acceptableExtensionsForSave]; [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)]; } else { [mOpenPanel setAllowedFileTypes:nil]; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel From b44df9937e4b15596b994f8e20822b83ac4bed29 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 30 Jan 2018 21:02:10 +0100 Subject: [PATCH 068/146] Clean-up in QDateTime's parsing of ISODate{,WithMs} Actually check that there's a T where ISO 8601 wants it (instead of just skipping over whatever's there), with something after it; move some declarations later; add some comments; and use the QStringRef API more cleanly (so that it's easier to see what's going on). Simplify a loop condition to avoid the need for a post-loop fix-up. This incidentally prevents an assertion failure (which brought the mess to my attention) parsing a short string as an ISO date-time; if there's a T with nothing after it, we won't try to read at index -1 in the following text. (The actual fail seen had a Z where the T should have been, with nothing after it.) Add tests for invalid ISOdate cases that triggered the assertion. Task-number: QTBUG-66076 Change-Id: Ided9adf62a56d98f144bdf91b40f918e22bd82cd Reviewed-by: Israel Lins Albuquerque Reviewed-by: Thiago Macieira (cherry picked from commit a9c111ed8c30a5a8fec3f02244f0d5a4bd08e931) --- src/corelib/tools/qdatetime.cpp | 23 +++++++++++++------ .../corelib/tools/qdatetime/tst_qdatetime.cpp | 4 ++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 9d26207a0f0..045ad107552 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -4720,25 +4720,35 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) if (size < 10) return QDateTime(); - QStringRef isoString(&string); - Qt::TimeSpec spec = Qt::LocalTime; - QDate date = QDate::fromString(string.left(10), Qt::ISODate); if (!date.isValid()) return QDateTime(); if (size == 10) return QDateTime(date); - isoString = isoString.right(isoString.length() - 11); + Qt::TimeSpec spec = Qt::LocalTime; + QStringRef isoString(&string); + isoString = isoString.mid(10); // trim "yyyy-MM-dd" + + // Must be left with T and at least one digit for the hour: + if (isoString.size() < 2 + || !(isoString.startsWith(QLatin1Char('T')) + // FIXME: QSql relies on QVariant::toDateTime() accepting a space here: + || isoString.startsWith(QLatin1Char(' ')))) { + return QDateTime(); + } + isoString = isoString.mid(1); // trim 'T' (or space) + int offset = 0; // Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset if (isoString.endsWith(QLatin1Char('Z'))) { spec = Qt::UTC; - isoString = isoString.left(isoString.size() - 1); + isoString.chop(1); // trim 'Z' } else { // the loop below is faster but functionally equal to: // const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]"))); int signIndex = isoString.size() - 1; + Q_ASSERT(signIndex >= 0); bool found = false; { const QChar plus = QLatin1Char('+'); @@ -4746,8 +4756,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) do { QChar character(isoString.at(signIndex)); found = character == plus || character == minus; - } while (--signIndex >= 0 && !found); - ++signIndex; + } while (!found && --signIndex >= 0); } if (found) { diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 28ad2d193c0..91b5966fa8d 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -2277,6 +2277,10 @@ void tst_QDateTime::fromStringDateFormat_data() QTest::newRow("ISO .99999 of a minute (comma)") << QString::fromLatin1("2012-01-01T08:00,99999") << Qt::ISODate << QDateTime(QDate(2012, 1, 1), QTime(8, 0, 59, 999), Qt::LocalTime); QTest::newRow("ISO empty") << QString::fromLatin1("") << Qt::ISODate << invalidDateTime(); + QTest::newRow("ISO short") << QString::fromLatin1("2017-07-01T") << Qt::ISODate << invalidDateTime(); + QTest::newRow("ISO zoned date") << QString::fromLatin1("2017-07-01Z") << Qt::ISODate << invalidDateTime(); + QTest::newRow("ISO zoned empty time") << QString::fromLatin1("2017-07-01TZ") << Qt::ISODate << invalidDateTime(); + QTest::newRow("ISO mis-punctuated") << QString::fromLatin1("2018/01/30 ") << Qt::ISODate << invalidDateTime(); // Test Qt::RFC2822Date format (RFC 2822). QTest::newRow("RFC 2822 +0100") << QString::fromLatin1("13 Feb 1987 13:24:51 +0100") From eadf9e542fcc42597bfe02df065fc4cefa94cd56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Tue, 30 Jan 2018 16:40:26 +0100 Subject: [PATCH 069/146] Android: Don't rely on QDir::homePath() to get the application directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the QLoggingRegistry gets called as part of the static initialization phase, it would call into Android's QStandarPaths implementation, which assumed that the HOME env. variable was already set. Since the variable isn't set before main is called, QDir::homePath() returns the root path, which would be cached and always returned. With this fix we now call Android's getFilesDir() directly, which will always return the right path. Since the font locations are also relying on an environment variable being set, we no longer cache that either. Task-number: QTBUG-65820 Change-Id: If45f3d5f0e87b808a62118ae95c31b492885646a Reviewed-by: Tor Arne Vestbø Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/io/qstandardpaths_android.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp index 2a44daf8b52..0667d170c71 100644 --- a/src/corelib/io/qstandardpaths_android.cpp +++ b/src/corelib/io/qstandardpaths_android.cpp @@ -217,7 +217,16 @@ static QString getFilesDir() if (!path.isEmpty()) return path; - return (path = QDir::homePath()); + QJNIObjectPrivate appCtx = applicationContext(); + if (!appCtx.isValid()) + return QString(); + + QJNIObjectPrivate file = appCtx.callObjectMethod("getFilesDir", + "()Ljava/io/File;"); + if (!file.isValid()) + return QString(); + + return (path = getAbsolutePath(file)); } QString QStandardPaths::writableLocation(StandardLocation type) @@ -319,7 +328,9 @@ QStringList QStandardPaths::standardLocations(StandardLocation type) if (!ba.isEmpty()) return QStringList((fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba)))); - return QStringList((fontLocation = QLatin1String("/system/fonts"))); + // Don't cache the fallback, as we might just have been called before + // QT_ANDROID_FONT_LOCATION has been set. + return QStringList(QLatin1String("/system/fonts")); } return QStringList(writableLocation(type)); From 69d2501ee1900c43a35802eae05a734e479a7776 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 29 Jan 2018 23:56:05 -0800 Subject: [PATCH 070/146] Revert "QVariant: convert QDateTime and QTime to string with milliseconds" This reverts commit ab1e50757454b5afda2f6dec52d2eb16a32d4798. That was supposed to be a minor behavior change, but ends up having visible effects such as QtXmlPatterns xs:dateTime type now reporting sub-second fractions. So we're reverting in 5.10 and re-applying in 5.11. Change-Id: I741e49459c9a688c1c329d6cbd521cd4a0b2aa84 Reviewed-by: Lars Knoll --- src/corelib/kernel/qvariant.cpp | 4 ++-- tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 10 ++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 93736ae8072..29429b5e551 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -440,10 +440,10 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok) *str = v_cast(d)->toString(Qt::ISODate); break; case QVariant::Time: - *str = v_cast(d)->toString(Qt::ISODateWithMs); + *str = v_cast(d)->toString(Qt::ISODate); break; case QVariant::DateTime: - *str = v_cast(d)->toString(Qt::ISODateWithMs); + *str = v_cast(d)->toString(Qt::ISODate); break; #endif case QVariant::Bool: diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 6ec90a66c85..0d45159d09c 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -1099,9 +1099,8 @@ void tst_QVariant::toString_data() QTest::newRow( "bool" ) << QVariant( true ) << QString( "true" ); QTest::newRow( "qdate" ) << QVariant( QDate( 2002, 1, 1 ) ) << QString( "2002-01-01" ); - QTest::newRow( "qtime" ) << QVariant( QTime( 12, 34, 56 ) ) << QString( "12:34:56.000" ); - QTest::newRow( "qtime-with-ms" ) << QVariant( QTime( 12, 34, 56, 789 ) ) << QString( "12:34:56.789" ); - QTest::newRow( "qdatetime" ) << QVariant( QDateTime( QDate( 2002, 1, 1 ), QTime( 12, 34, 56, 789 ) ) ) << QString( "2002-01-01T12:34:56.789" ); + QTest::newRow( "qtime" ) << QVariant( QTime( 12, 34, 56 ) ) << QString( "12:34:56" ); + QTest::newRow( "qdatetime" ) << QVariant( QDateTime( QDate( 2002, 1, 1 ), QTime( 12, 34, 56 ) ) ) << QString( "2002-01-01T12:34:56" ); QTest::newRow( "llong" ) << QVariant( (qlonglong)Q_INT64_C(123456789012) ) << QString( "123456789012" ); QTest::newRow("QJsonValue") << QVariant(QJsonValue(QString("hello"))) << QString("hello"); @@ -1152,7 +1151,6 @@ void tst_QVariant::toTime_data() QTest::newRow( "qtime" ) << QVariant( QTime( 12, 34, 56 ) ) << QTime( 12, 34, 56 ); QTest::newRow( "qdatetime" ) << QVariant( QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56 ) ) ) << QTime( 12, 34, 56 ); QTest::newRow( "qstring" ) << QVariant( QString( "12:34:56" ) ) << QTime( 12, 34, 56 ); - QTest::newRow( "qstring-with-ms" ) << QVariant( QString( "12:34:56.789" ) ) << QTime( 12, 34, 56, 789 ); } void tst_QVariant::toTime() @@ -1173,10 +1171,6 @@ void tst_QVariant::toDateTime_data() << QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56 ) ); QTest::newRow( "qdate" ) << QVariant( QDate( 2002, 10, 10 ) ) << QDateTime( QDate( 2002, 10, 10 ), QTime( 0, 0, 0 ) ); QTest::newRow( "qstring" ) << QVariant( QString( "2002-10-10T12:34:56" ) ) << QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56 ) ); - QTest::newRow( "qstring-utc" ) << QVariant( QString( "2002-10-10T12:34:56Z" ) ) - << QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56 ), Qt::UTC ); - QTest::newRow( "qstring-with-ms" ) << QVariant( QString( "2002-10-10T12:34:56.789" ) ) - << QDateTime( QDate( 2002, 10, 10 ), QTime( 12, 34, 56, 789 ) ); } void tst_QVariant::toDateTime() From 1f0c22844811d71fae69ee6b103bbfc5e750ca90 Mon Sep 17 00:00:00 2001 From: Dominik Haumann Date: Mon, 29 Jan 2018 19:38:49 +0100 Subject: [PATCH 071/146] Fix window activation in QWindowsWindow::setCustomMargins() Currently, code paths that call QWindowsWindow:setCustomMargins() automatically also activate the window (=give the window focus). The reason for this is the call of SetWindowPos (Windows API) without the flag SWP_NOACTIVATE. From the Windows API documentation about SetWindowPos() about the flag SWP_NOACTIVATE: Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). It seems the flag SWP_NOACTIVATE is accidentally missing in the call of SetWindowPos() in setCustomMargins(), especially since the flag is present in pretty much all other calls of SetWindowPos(). The obvious fix is to add the flag SWP_NOACTIVATE to the call of SetWindowPos() in setCustomMargins(). So far, this issue exists for a long time, an was possibly introduced with commit f5fd5346038, where setCustomMargins() was initially added. Change-Id: Id3f058f8762df17eb3f033ab0b3e1791283937fc Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowswindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 402009c70d4..c1aeecf0ab4 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2401,7 +2401,7 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) newFrame.moveTo(topLeft); qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins << currentFrameGeometry << "->" << newFrame; - SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED); + SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE); } } From b7e436738756b1d5d7a45201b7a7204d7fe128a1 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Mon, 22 Jan 2018 18:51:57 +0200 Subject: [PATCH 072/146] Fix some cases of scaled text disappearing with freetype Commit a56ee60791538e5442b3d97b75270b25dc4986db changed type of advance to short, restoring this fixes at least some cases where glyphs were disappearing. Task-number: QTBUG-65838 Change-Id: I33b252d91fb7541eaea3275b1950a048941869a6 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp | 4 +--- src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp index 2c5850b6ad7..3f543755b61 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp @@ -994,9 +994,7 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags, static inline bool areMetricsTooLarge(const QFontEngineFT::GlyphInfo &info) { // false if exceeds QFontEngineFT::Glyph metrics - return (short)(info.linearAdvance) != info.linearAdvance - || (uchar)(info.width) != info.width - || (uchar)(info.height) != info.height; + return info.width > 0xFF || info.height > 0xFF; } static inline void transformBoundingBox(int *left, int *top, int *right, int *bottom, FT_Matrix *matrix) diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h index c063f5df30c..e98268ae4bc 100644 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h +++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h @@ -133,7 +133,7 @@ public: /* we don't cache glyphs that are too large anyway, so we can make this struct rather small */ struct Glyph { ~Glyph(); - short linearAdvance; + int linearAdvance : 22; unsigned char width; unsigned char height; short x; From e365993b72d64db441f3940d6c255e3dbb2ad76a Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 1 Feb 2018 16:12:49 +0100 Subject: [PATCH 073/146] Fix configure.json for opensslv11 feature Both the test/feature had some errors (incorrect "use" and incomplete "condition") + remove "feature". Task-number: QTBUG-62733 Change-Id: If4b8d2fe080d8fba961231834839afadaed0f0c5 Reviewed-by: Oswald Buddenhagen --- src/network/configure.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/network/configure.json b/src/network/configure.json index 770921f9a61..2f446becf1b 100644 --- a/src/network/configure.json +++ b/src/network/configure.json @@ -123,10 +123,10 @@ "use": "network" }, "openssl11": { - "label": "OpenSSL v. 1.1 support", + "label": "OpenSSL 1.1 support", "type": "compile", "test": "unix/openssl11", - "use": "network" + "use": "openssl" } }, @@ -190,9 +190,9 @@ "output": [ "publicFeature", "feature" ] }, "opensslv11": { - "label": "OpenSSL v. 1.1", - "condition": "tests.openssl11", - "output": ["publicFeature", "feature"] + "label": "OpenSSL 1.1", + "condition": "features.openssl && tests.openssl11", + "output": [ "publicFeature" ] }, "sctp": { "label": "SCTP", @@ -307,6 +307,7 @@ For example: }, "openssl", "openssl-linked", + "opensslv11", "sctp", "system-proxies" ] From 1514b4e85336245ef130deca5839267dba7b2e32 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 29 Jan 2018 21:46:40 -0800 Subject: [PATCH 074/146] Silence GCC 8 warning on memcpy of class Value to to class offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From GCC 8: error: ‘void* memcpy(void*, const void*, size_t)’ copying an object of type ‘QJsonPrivate::offset’ {aka ‘class QSpecialInteger >’} with ‘private’ member ‘QSpecialInteger >::val’ from an array of ‘const value_type’ {aka ‘const class QJsonPrivate::Value’}; use assignment or copy-initialization instead [-Werror=class-memaccess] Both types are standard layout and have the same initial sequence (one uint member), so this is a valid copy. The only difference between the two is that QSpecialInteger has a private member, whereas in the bitfield it's public. Change-Id: I41d006aac5bc48529845fffd150e80585fd24db7 Reviewed-by: Ville Voutilainen Reviewed-by: Thiago Macieira --- src/corelib/json/qjsonarray.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp index d4cc4b81df0..255dc2ee4e8 100644 --- a/src/corelib/json/qjsonarray.cpp +++ b/src/corelib/json/qjsonarray.cpp @@ -297,7 +297,8 @@ QJsonArray QJsonArray::fromVariantList(const QVariantList &list) array.a->tableOffset = currentOffset; if (!array.detach2(sizeof(QJsonPrivate::offset)*values.size())) return QJsonArray(); - memcpy(array.a->table(), values.constData(), values.size()*sizeof(uint)); + memcpy(static_cast(array.a->table()), + static_cast(values.constData()), values.size()*sizeof(uint)); array.a->length = values.size(); array.a->size = currentOffset + sizeof(QJsonPrivate::offset)*values.size(); From c26c5b7d0dc4607b7cdd5569c5180b94b4563b73 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 29 Jan 2018 21:46:40 -0800 Subject: [PATCH 075/146] Silence GCC 8 warning on memcpy of movable types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is similar to commit 342bb5b03a76d1428fafb8e1532d66e172bd1c0b. From GCC 8: qarraydataops.h:84:17: error: ‘void* memcpy(void*, const void*, size_t)’ writing to an object of type ‘class QStringRef’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Werror=class-memaccess] [etc.] Change-Id: I41d006aac5bc48529845fffd150e817e64973bec Reviewed-by: Ville Voutilainen Reviewed-by: Thiago Macieira --- src/corelib/tools/qarraydataops.h | 3 ++- src/corelib/tools/qvarlengtharray.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index b7c3bc1287c..d0f83d2b6a9 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -76,7 +76,8 @@ struct QPodArrayOps Q_ASSERT(b < e); Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size)); - ::memcpy(this->end(), b, (e - b) * sizeof(T)); + ::memcpy(static_cast(this->end()), static_cast(b), + (e - b) * sizeof(T)); this->size += e - b; } diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index d99eebd4b94..58bb5e75c47 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -344,7 +344,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::append(const T *abuf, in while (s < asize) new (ptr+(s++)) T(*abuf++); } else { - memcpy(&ptr[s], abuf, increment * sizeof(T)); + memcpy(static_cast(&ptr[s]), static_cast(abuf), increment * sizeof(T)); s = asize; } } @@ -392,7 +392,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::realloc(int asize, int a QT_RETHROW; } } else { - memcpy(ptr, oldPtr, copySize * sizeof(T)); + memcpy(static_cast(ptr), static_cast(oldPtr), copySize * sizeof(T)); } } s = copySize; From 403343039d07812c0beee9260b291f86e14d8ac4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 29 Jan 2018 22:00:46 -0800 Subject: [PATCH 076/146] Suppress GCC 8 warning about realloc() non-trivially-copyable types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit But they are movable. qxmlstream_p.h:654:32: error: ‘void* realloc(void*, size_t)’ moving an object of non-trivially copyable type ‘struct QXmlStreamPrivateTagStack::Tag’; use ‘new’ and ‘delete’ instead [-Werror=class-memaccess] Change-Id: I41d006aac5bc48529845fffd150e8115eb852034 Reviewed-by: Ville Voutilainen Reviewed-by: Thiago Macieira --- src/corelib/xml/qxmlstream_p.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/xml/qxmlstream_p.h b/src/corelib/xml/qxmlstream_p.h index 9ef95c1fbe6..e6c89e40cd5 100644 --- a/src/corelib/xml/qxmlstream_p.h +++ b/src/corelib/xml/qxmlstream_p.h @@ -651,7 +651,8 @@ public: inline void reserve(int extraCapacity) { if (tos + extraCapacity + 1 > cap) { cap = qMax(tos + extraCapacity + 1, cap << 1 ); - data = reinterpret_cast(realloc(data, cap * sizeof(T))); + void *ptr = realloc(static_cast(data), cap * sizeof(T)); + data = reinterpret_cast(ptr); Q_CHECK_PTR(data); } } From 9a74cbf47386a861b44900cda2c5a00b4ffd42d8 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Thu, 1 Feb 2018 21:47:42 +0100 Subject: [PATCH 077/146] QString: Wrap extra-long comment line Change-Id: I77c95e99fd23eb914d7e86ee003d7f487c57f0f0 Reviewed-by: Martin Smith --- src/corelib/tools/qstring.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 30f8948eecc..99262444973 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -6951,7 +6951,10 @@ ushort QString::toUShort(bool *ok, int base) const \snippet qstring/main.cpp 66 - \warning The QString content may only contain valid numerical characters which includes the plus/minus sign, the characters g and e used in scientific notation, and the decimal point. Including the unit or additional characters leads to a conversion error. + \warning The QString content may only contain valid numerical characters + which includes the plus/minus sign, the characters g and e used in scientific + notation, and the decimal point. Including the unit or additional characters + leads to a conversion error. \snippet qstring/main.cpp 67 From 6197df32ec3449ec141bcd9fa4fe47da4cc761e7 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Thu, 1 Feb 2018 21:37:56 +0100 Subject: [PATCH 078/146] QString: Add whitespace handling note to number conversion functions Copied from QLocale::toFloat and companions. Change-Id: Ic3a13a87cfc1ce34de9dd7d7e7b303ef103c384a Reviewed-by: Thiago Macieira --- src/corelib/tools/qstring.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 99262444973..1ef9f5a3c5c 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -6712,6 +6712,8 @@ QString QString::vasprintf(const char *cformat, va_list ap) \snippet qstring/main.cpp 74 + This function ignores leading and trailing whitespace. + \sa number(), toULongLong(), toInt(), QLocale::toLongLong() */ @@ -6752,6 +6754,8 @@ qlonglong QString::toIntegral_helper(const QChar *data, int len, bool *ok, int b \snippet qstring/main.cpp 79 + This function ignores leading and trailing whitespace. + \sa number(), toLongLong(), QLocale::toULongLong() */ @@ -6794,6 +6798,8 @@ qulonglong QString::toIntegral_helper(const QChar *data, uint len, bool *ok, int \snippet qstring/main.cpp 73 + This function ignores leading and trailing whitespace. + \sa number(), toULong(), toInt(), QLocale::toInt() */ @@ -6823,6 +6829,8 @@ long QString::toLong(bool *ok, int base) const \snippet qstring/main.cpp 78 + This function ignores leading and trailing whitespace. + \sa number(), QLocale::toUInt() */ @@ -6851,6 +6859,8 @@ ulong QString::toULong(bool *ok, int base) const \snippet qstring/main.cpp 72 + This function ignores leading and trailing whitespace. + \sa number(), toUInt(), toDouble(), QLocale::toInt() */ @@ -6878,6 +6888,8 @@ int QString::toInt(bool *ok, int base) const \snippet qstring/main.cpp 77 + This function ignores leading and trailing whitespace. + \sa number(), toInt(), QLocale::toUInt() */ @@ -6905,6 +6917,8 @@ uint QString::toUInt(bool *ok, int base) const \snippet qstring/main.cpp 76 + This function ignores leading and trailing whitespace. + \sa number(), toUShort(), toInt(), QLocale::toShort() */ @@ -6932,6 +6946,8 @@ short QString::toShort(bool *ok, int base) const \snippet qstring/main.cpp 80 + This function ignores leading and trailing whitespace. + \sa number(), toShort(), QLocale::toUShort() */ @@ -6969,6 +6985,8 @@ ushort QString::toUShort(bool *ok, int base) const \snippet qstring/main.cpp 69 + This function ignores leading and trailing whitespace. + \sa number(), QLocale::setDefault(), QLocale::toDouble(), trimmed() */ @@ -6983,6 +7001,8 @@ double QString::toDouble(bool *ok) const If a conversion error occurs, *\a{ok} is set to \c false; otherwise *\a{ok} is set to \c true. Returns 0.0 if the conversion fails. + This function ignores leading and trailing whitespace. + The string conversion will always happen in the 'C' locale. For locale dependent conversion use QLocale::toFloat() @@ -6990,6 +7010,8 @@ double QString::toDouble(bool *ok) const \snippet qstring/main.cpp 71 + This function ignores leading and trailing whitespace. + \sa number(), toDouble(), toInt(), QLocale::toFloat() */ From 35f6f530bfa3877dfdf763ab1cdb1d63cc66c6d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 24 Jan 2018 15:42:17 +0100 Subject: [PATCH 079/146] iOS: Simplify logging of QUIView/QIOSWindow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automatically printing the relationship between the view, platform window, and window, makes it easier to track each object across events. Change-Id: I9fbfaa5c304849ed99dba3b5cd8e7449105d0307 Reviewed-by: Richard Moe Gustavsen Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qioswindow.h | 4 +++ src/plugins/platforms/ios/qioswindow.mm | 13 +++++++++ src/plugins/platforms/ios/quiview.mm | 35 ++++++++++++++++--------- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 14fa2084c9a..8ed5347f66b 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -110,6 +110,10 @@ private: friend class QIOSScreen; }; +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QIOSWindow *window); +#endif + QT_END_NAMESPACE #endif // QIOSWINDOW_H diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 38136c05dbf..6ee258e363d 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -381,6 +381,19 @@ CAEAGLLayer *QIOSWindow::eaglLayer() const return static_cast(m_view.layer); } +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QIOSWindow *window) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug << "QIOSWindow(" << (const void *)window; + if (window) + debug << ", window=" << window->window(); + debug << ')'; + return debug; +} +#endif // !QT_NO_DEBUG_STREAM + #include "moc_qioswindow.cpp" QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 4c2184a1f63..bd75ed23840 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -147,6 +147,21 @@ [super dealloc]; } +- (NSString *)description +{ + NSMutableString *description = [NSMutableString stringWithString:[super description]]; + +#ifndef QT_NO_DEBUG_STREAM + QString platformWindowDescription; + QDebug debug(&platformWindowDescription); + debug.nospace() << "; " << m_qioswindow << ">"; + NSRange lastCharacter = [description rangeOfComposedCharacterSequenceAtIndex:description.length - 1]; + [description replaceCharactersInRange:lastCharacter withString:platformWindowDescription.toNSString()]; +#endif + + return description; +} + - (void)willMoveToWindow:(UIWindow *)newWindow { // UIKIt will normally set the scale factor of a view to match the corresponding @@ -191,13 +206,12 @@ // when the size is also changed. if (!CGAffineTransformIsIdentity(self.transform)) - qWarning() << m_qioswindow->window() - << "is backed by a UIView that has a transform set. This is not supported."; + qWarning() << self << "has a transform set. This is not supported."; QWindow *window = m_qioswindow->window(); QRect lastReportedGeometry = qt_window_private(window)->geometry; QRect currentGeometry = QRectF::fromCGRect(self.frame).toRect(); - qCDebug(lcQpaWindow) << m_qioswindow->window() << "new geometry is" << currentGeometry; + qCDebug(lcQpaWindow) << m_qioswindow << "new geometry is" << currentGeometry; QWindowSystemInterface::handleGeometryChange(window, currentGeometry); if (currentGeometry.size() != lastReportedGeometry.size()) { @@ -230,7 +244,7 @@ region = QRect(QPoint(), bounds); } - qCDebug(lcQpaWindow) << m_qioswindow->window() << region << "isExposed" << m_qioswindow->isExposed(); + qCDebug(lcQpaWindow) << m_qioswindow << region << "isExposed" << m_qioswindow->isExposed(); QWindowSystemInterface::handleExposeEvent(m_qioswindow->window(), region); } @@ -254,16 +268,14 @@ // blocked by this guard. FirstResponderCandidate firstResponderCandidate(self); - qImDebug() << "win:" << m_qioswindow->window() << "self:" << self - << "first:" << [UIResponder currentFirstResponder]; + qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder]; if (![super becomeFirstResponder]) { - qImDebug() << m_qioswindow->window() - << "was not allowed to become first responder"; + qImDebug() << self << "was not allowed to become first responder"; return NO; } - qImDebug() << m_qioswindow->window() << "became first responder"; + qImDebug() << self << "became first responder"; } if (qGuiApp->focusWindow() != m_qioswindow->window()) @@ -295,13 +307,12 @@ - (BOOL)resignFirstResponder { - qImDebug() << "win:" << m_qioswindow->window() << "self:" << self - << "first:" << [UIResponder currentFirstResponder]; + qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder]; if (![super resignFirstResponder]) return NO; - qImDebug() << m_qioswindow->window() << "resigned first responder"; + qImDebug() << self << "resigned first responder"; UIResponder *newResponder = FirstResponderCandidate::currentCandidate(); if ([self responderShouldTriggerWindowDeactivation:newResponder]) From 28cf5ae000de36cd6ad0df942c2f99bfa7e22129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 22 Jan 2018 17:34:03 +0100 Subject: [PATCH 080/146] macOS: Share view update code between layered and non-layered mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I8eaf0607c1ede18ed20180fd43cc93744c99962d Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qnsview.mm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index e3bee95ad9a..3e3e9aac1ad 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -334,7 +334,11 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect(); qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion; + [self updateRegion:exposedRegion]; +} +- (void)updateRegion:(QRegion)dirtyRegion +{ #ifndef QT_NO_OPENGL if (m_glContext && m_shouldSetGLContextinDrawRect) { [m_glContext->nsOpenGLContext() setView:self]; @@ -350,7 +354,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") windowPrivate->deliverUpdateRequest(); m_updateRequested = false; } else { - m_platformWindow->handleExposeEvent(exposedRegion); + m_platformWindow->handleExposeEvent(dirtyRegion); } if (windowPrivate->updateRequestPending) { @@ -376,7 +380,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") qCDebug(lcQpaCocoaWindow) << "[QNSView updateLayer]" << m_platformWindow->window(); // FIXME: Find out if there's a way to resolve the dirty rect like in drawRect: - m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect()); + [self updateRegion:QRectF::fromCGRect(self.bounds).toRect()]; } - (void)viewDidChangeBackingProperties From 756ebcd93a028bd9c731acddbea09de67c2410e3 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Feb 2018 14:37:32 +0100 Subject: [PATCH 081/146] QGtk3Menu::showPopup(): fix off by one error in the y-coordinate QRect::bottom() != QRect::y() + QRect::height() Change-Id: I83ae19ab588fb9651354999679f5d3c9e294a97e Reviewed-by: Friedemann Kleint --- src/plugins/platformthemes/gtk3/qgtk3menu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp index f48e00ab8e2..99407a21de1 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp +++ b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp @@ -448,7 +448,8 @@ void QGtk3Menu::showPopup(const QWindow *parentWindow, const QRect &targetRect, if (index != -1) gtk_menu_set_active(GTK_MENU(m_menu), index); - m_targetPos = targetRect.bottomLeft(); + m_targetPos = QPoint(targetRect.x(), targetRect.y() + targetRect.height()); + if (parentWindow) m_targetPos = parentWindow->mapToGlobal(m_targetPos); From 57f4521c99df1e4e2c1fd321a41019ae4e0c17b1 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Feb 2018 08:06:04 +0100 Subject: [PATCH 082/146] Fix QXcbWindow::mapFrom/ToGlobal() Call the base class implementations to avoid returning an unmapped values for non-embedded windows. Task-number: QTBUG-55251 Change-Id: Ib05fd530498dd4d72d3d4ef37caf4e2f0ebcd2e4 Reviewed-by: Friedemann Kleint Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index c4649ac8185..37d6336a724 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2157,7 +2157,7 @@ bool QXcbWindow::isEmbedded() const QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const { if (!m_embedded) - return pos; + return QPlatformWindow::mapToGlobal(pos); QPoint ret; xcb_translate_coordinates_cookie_t cookie = @@ -2177,7 +2177,7 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const { if (!m_embedded) - return pos; + return QPlatformWindow::mapFromGlobal(pos); QPoint ret; xcb_translate_coordinates_cookie_t cookie = From 1ffc6ba402114a3443df5309dec186fd337e5b66 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Feb 2018 08:50:15 +0100 Subject: [PATCH 083/146] macOS: fix menu positioning on high-DPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The target position is passed in physical native pixels, so call QPlatformScreen::availableGeometry() and QPlatformWindow::mapToGlobal() instead of QScreen::availableSize() and QWindow::mapToGlobal(). The latter two operate on logical pixels. Task-number: QTBUG-55251 Change-Id: I281f47baee727bc0f4738fd6d6cdf12c9f462b0f Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoamenu.mm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 8bdd0512de4..e41c70b8cab 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -46,6 +46,7 @@ #include #include #include "qcocoaapplication.h" +#include "qcocoaintegration.h" #include "qcocoamenuloader.h" #include "qcocoamenubar.h" #include "qcocoawindow.h" @@ -573,8 +574,9 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, [popupCell setMenu:m_nativeMenu]; [popupCell selectItem:nsItem]; - int availableHeight = screen->availableSize().height(); - const QPoint &globalPos = parentWindow->mapToGlobal(pos); + QCocoaScreen *cocoaScreen = static_cast(screen->handle()); + int availableHeight = cocoaScreen->availableGeometry().height(); + const QPoint &globalPos = cocoaWindow->mapToGlobal(pos); int menuHeight = m_nativeMenu.size.height; if (globalPos.y() + menuHeight > availableHeight) { // Maybe we need to fix the vertical popup position but we don't know the From 1cc15c4b6d65a22ab4018226a96baf843feb1f00 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Feb 2018 10:00:27 +0100 Subject: [PATCH 084/146] QComboBoxPrivate::showNativePopup(): Scale target rectangle The QPlatform* classes operate in native pixels. Task-number: QTBUG-55251 Change-Id: I80490fa802fbc77a1e02c176528cc047630f9a7d Reviewed-by: Friedemann Kleint --- src/widgets/widgets/qcombobox.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index e0bc198d2ec..7ab3565a00f 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -2550,7 +2551,8 @@ bool QComboBoxPrivate::showNativePopup() else if (q->testAttribute(Qt::WA_MacMiniSize)) offset = QPoint(-2, 6); - m_platformMenu->showPopup(tlw, QRect(tlw->mapFromGlobal(q->mapToGlobal(offset)), QSize()), currentItem); + const QRect targetRect = QRect(tlw->mapFromGlobal(q->mapToGlobal(offset)), QSize()); + m_platformMenu->showPopup(tlw, QHighDpi::toNativePixels(targetRect, tlw), currentItem); #ifdef Q_OS_OSX // The Cocoa popup will swallow any mouse release event. From 0307bfea31782512939aa4f97425b57cf35c080c Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 29 Jan 2018 14:54:19 +0100 Subject: [PATCH 085/146] ANGLE: Remove workaround for files having the same name (Debug.h/.cpp) With object_parallel_to_source the workaround of making copies of the files and using these is no longer needed. Debug2.h and .cpp were added to the repository by mistake and should not have been there in the first place. Task-number: QTBUG-66059 Change-Id: Ib9dbd15be1dee1cb5190762fe06bad56dd40dd47 Reviewed-by: Joerg Bornemann --- src/3rdparty/angle/src/libANGLE/Debug2.cpp | 303 --------------------- src/3rdparty/angle/src/libANGLE/Debug2.h | 120 -------- src/angle/src/common/gles_common.pri | 12 +- 3 files changed, 3 insertions(+), 432 deletions(-) delete mode 100644 src/3rdparty/angle/src/libANGLE/Debug2.cpp delete mode 100644 src/3rdparty/angle/src/libANGLE/Debug2.h diff --git a/src/3rdparty/angle/src/libANGLE/Debug2.cpp b/src/3rdparty/angle/src/libANGLE/Debug2.cpp deleted file mode 100644 index 30321f41606..00000000000 --- a/src/3rdparty/angle/src/libANGLE/Debug2.cpp +++ /dev/null @@ -1,303 +0,0 @@ -// -// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Debug.cpp: Defines debug state used for GL_KHR_debug - -#include "libANGLE/Debug.h" - -#include "common/debug.h" - -#include -#include - -namespace gl -{ - -Debug::Debug() - : mOutputEnabled(false), - mCallbackFunction(nullptr), - mCallbackUserParam(nullptr), - mMessages(), - mMaxLoggedMessages(0), - mOutputSynchronous(false), - mGroups() -{ - pushDefaultGroup(); -} - -void Debug::setMaxLoggedMessages(GLuint maxLoggedMessages) -{ - mMaxLoggedMessages = maxLoggedMessages; -} - -void Debug::setOutputEnabled(bool enabled) -{ - mOutputEnabled = enabled; -} - -bool Debug::isOutputEnabled() const -{ - return mOutputEnabled; -} - -void Debug::setOutputSynchronous(bool synchronous) -{ - mOutputSynchronous = synchronous; -} - -bool Debug::isOutputSynchronous() const -{ - return mOutputSynchronous; -} - -void Debug::setCallback(GLDEBUGPROCKHR callback, const void *userParam) -{ - mCallbackFunction = callback; - mCallbackUserParam = userParam; -} - -GLDEBUGPROCKHR Debug::getCallback() const -{ - return mCallbackFunction; -} - -const void *Debug::getUserParam() const -{ - return mCallbackUserParam; -} - -void Debug::insertMessage(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - const std::string &message) -{ - std::string messageCopy(message); - insertMessage(source, type, id, severity, std::move(messageCopy)); -} - -void Debug::insertMessage(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - std::string &&message) -{ - if (!isMessageEnabled(source, type, id, severity)) - { - return; - } - - if (mCallbackFunction != nullptr) - { - // TODO(geofflang) Check the synchronous flag and potentially flush messages from another - // thread. - mCallbackFunction(source, type, id, severity, static_cast(message.length()), - message.c_str(), mCallbackUserParam); - } - else - { - if (mMessages.size() >= mMaxLoggedMessages) - { - // Drop messages over the limit - return; - } - - Message m; - m.source = source; - m.type = type; - m.id = id; - m.severity = severity; - m.message = std::move(message); - - mMessages.push_back(std::move(m)); - } -} - -size_t Debug::getMessages(GLuint count, - GLsizei bufSize, - GLenum *sources, - GLenum *types, - GLuint *ids, - GLenum *severities, - GLsizei *lengths, - GLchar *messageLog) -{ - size_t messageCount = 0; - size_t messageStringIndex = 0; - while (messageCount <= count && !mMessages.empty()) - { - const Message &m = mMessages.front(); - - if (messageLog != nullptr) - { - // Check that this message can fit in the message buffer - if (messageStringIndex + m.message.length() + 1 > static_cast(bufSize)) - { - break; - } - - std::copy(m.message.begin(), m.message.end(), messageLog + messageStringIndex); - messageStringIndex += m.message.length(); - - messageLog[messageStringIndex] = '\0'; - messageStringIndex += 1; - } - - if (sources != nullptr) - { - sources[messageCount] = m.source; - } - - if (types != nullptr) - { - types[messageCount] = m.type; - } - - if (ids != nullptr) - { - ids[messageCount] = m.id; - } - - if (severities != nullptr) - { - severities[messageCount] = m.severity; - } - - if (lengths != nullptr) - { - lengths[messageCount] = static_cast(m.message.length()); - } - - mMessages.pop_front(); - - messageCount++; - } - - return messageCount; -} - -size_t Debug::getNextMessageLength() const -{ - return mMessages.empty() ? 0 : mMessages.front().message.length(); -} - -size_t Debug::getMessageCount() const -{ - return mMessages.size(); -} - -void Debug::setMessageControl(GLenum source, - GLenum type, - GLenum severity, - std::vector &&ids, - bool enabled) -{ - Control c; - c.source = source; - c.type = type; - c.severity = severity; - c.ids = std::move(ids); - c.enabled = enabled; - - auto &controls = mGroups.back().controls; - controls.push_back(std::move(c)); -} - -void Debug::pushGroup(GLenum source, GLuint id, std::string &&message) -{ - insertMessage(source, GL_DEBUG_TYPE_PUSH_GROUP, id, GL_DEBUG_SEVERITY_NOTIFICATION, - std::string(message)); - - Group g; - g.source = source; - g.id = id; - g.message = std::move(message); - mGroups.push_back(std::move(g)); -} - -void Debug::popGroup() -{ - // Make sure the default group is not about to be popped - ASSERT(mGroups.size() > 1); - - Group g = mGroups.back(); - mGroups.pop_back(); - - insertMessage(g.source, GL_DEBUG_TYPE_POP_GROUP, g.id, GL_DEBUG_SEVERITY_NOTIFICATION, - g.message); -} - -size_t Debug::getGroupStackDepth() const -{ - return mGroups.size(); -} - -bool Debug::isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const -{ - if (!mOutputEnabled) - { - return false; - } - - for (auto groupIter = mGroups.rbegin(); groupIter != mGroups.rend(); groupIter++) - { - const auto &controls = groupIter->controls; - for (auto controlIter = controls.rbegin(); controlIter != controls.rend(); controlIter++) - { - const auto &control = *controlIter; - - if (control.source != GL_DONT_CARE && control.source != source) - { - continue; - } - - if (control.type != GL_DONT_CARE && control.type != type) - { - continue; - } - - if (control.severity != GL_DONT_CARE && control.severity != severity) - { - continue; - } - - if (!control.ids.empty() && - std::find(control.ids.begin(), control.ids.end(), id) == control.ids.end()) - { - continue; - } - - return control.enabled; - } - } - - return true; -} - -void Debug::pushDefaultGroup() -{ - Group g; - g.source = GL_NONE; - g.id = 0; - g.message = ""; - - Control c0; - c0.source = GL_DONT_CARE; - c0.type = GL_DONT_CARE; - c0.severity = GL_DONT_CARE; - c0.enabled = true; - g.controls.push_back(std::move(c0)); - - Control c1; - c1.source = GL_DONT_CARE; - c1.type = GL_DONT_CARE; - c1.severity = GL_DEBUG_SEVERITY_LOW; - c1.enabled = false; - g.controls.push_back(std::move(c1)); - - mGroups.push_back(std::move(g)); -} -} // namespace gl diff --git a/src/3rdparty/angle/src/libANGLE/Debug2.h b/src/3rdparty/angle/src/libANGLE/Debug2.h deleted file mode 100644 index f545b815e4e..00000000000 --- a/src/3rdparty/angle/src/libANGLE/Debug2.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// - -// Debug.h: Defines debug state used for GL_KHR_debug - -#ifndef LIBANGLE_DEBUG_H_ -#define LIBANGLE_DEBUG_H_ - -#include "angle_gl.h" -#include "common/angleutils.h" - -#include -#include -#include - -namespace gl -{ - -class LabeledObject -{ - public: - virtual ~LabeledObject() {} - virtual void setLabel(const std::string &label) = 0; - virtual const std::string &getLabel() const = 0; -}; - -class Debug : angle::NonCopyable -{ - public: - Debug(); - - void setMaxLoggedMessages(GLuint maxLoggedMessages); - - void setOutputEnabled(bool enabled); - bool isOutputEnabled() const; - - void setOutputSynchronous(bool synchronous); - bool isOutputSynchronous() const; - - void setCallback(GLDEBUGPROCKHR callback, const void *userParam); - GLDEBUGPROCKHR getCallback() const; - const void *getUserParam() const; - - void insertMessage(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - const std::string &message); - void insertMessage(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - std::string &&message); - - void setMessageControl(GLenum source, - GLenum type, - GLenum severity, - std::vector &&ids, - bool enabled); - size_t getMessages(GLuint count, - GLsizei bufSize, - GLenum *sources, - GLenum *types, - GLuint *ids, - GLenum *severities, - GLsizei *lengths, - GLchar *messageLog); - size_t getNextMessageLength() const; - size_t getMessageCount() const; - - void pushGroup(GLenum source, GLuint id, std::string &&message); - void popGroup(); - size_t getGroupStackDepth() const; - - private: - bool isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const; - - void pushDefaultGroup(); - - struct Message - { - GLenum source; - GLenum type; - GLuint id; - GLenum severity; - std::string message; - }; - - struct Control - { - GLenum source; - GLenum type; - GLenum severity; - std::vector ids; - bool enabled; - }; - - struct Group - { - GLenum source; - GLuint id; - std::string message; - - std::vector controls; - }; - - bool mOutputEnabled; - GLDEBUGPROCKHR mCallbackFunction; - const void *mCallbackUserParam; - std::deque mMessages; - GLuint mMaxLoggedMessages; - bool mOutputSynchronous; - std::vector mGroups; -}; -} // namespace gl - -#endif // LIBANGLE_DEBUG_H_ diff --git a/src/angle/src/common/gles_common.pri b/src/angle/src/common/gles_common.pri index 5d5682a1df5..82d38a62e6f 100644 --- a/src/angle/src/common/gles_common.pri +++ b/src/angle/src/common/gles_common.pri @@ -1,4 +1,4 @@ -CONFIG += simd no_batch +CONFIG += simd no_batch object_parallel_to_source include(common.pri) INCLUDEPATH += $$OUT_PWD/.. $$ANGLE_DIR/src/libANGLE @@ -48,6 +48,7 @@ HEADERS += \ $$ANGLE_DIR/src/libANGLE/Constants.h \ $$ANGLE_DIR/src/libANGLE/Context.h \ $$ANGLE_DIR/src/libANGLE/Data.h \ + $$ANGLE_DIR/src/libANGLE/Debug.h \ $$ANGLE_DIR/src/libANGLE/Device.h \ $$ANGLE_DIR/src/libANGLE/Display.h \ $$ANGLE_DIR/src/libANGLE/Error.h \ @@ -169,6 +170,7 @@ SOURCES += \ $$ANGLE_DIR/src/libANGLE/Config.cpp \ $$ANGLE_DIR/src/libANGLE/Context.cpp \ $$ANGLE_DIR/src/libANGLE/Data.cpp \ + $$ANGLE_DIR/src/libANGLE/Debug.cpp \ $$ANGLE_DIR/src/libANGLE/Device.cpp \ $$ANGLE_DIR/src/libANGLE/Display.cpp \ $$ANGLE_DIR/src/libANGLE/Error.cpp \ @@ -241,14 +243,6 @@ SOURCES += \ SSE2_SOURCES += $$ANGLE_DIR/src/libANGLE/renderer/d3d/loadimageSSE2.cpp -DEBUG_SOURCE = $$ANGLE_DIR/src/libANGLE/Debug.cpp -debug_copy.input = DEBUG_SOURCE -debug_copy.output = $$ANGLE_DIR/src/libANGLE/Debug2.cpp -debug_copy.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} -debug_copy.variable_out = GENERATED_SOURCES -debug_copy.CONFIG = target_predeps -QMAKE_EXTRA_COMPILERS += debug_copy - angle_d3d11 { HEADERS += \ $$ANGLE_DIR/src/libANGLE/renderer/d3d/d3d11/Blit11.h \ From fef6b31b994befac0ee14391572ebc2b9b33e104 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Feb 2018 14:40:46 +0100 Subject: [PATCH 086/146] GTK: fix menu positioning on high-DPI The target position is passed in physical native pixels, so call QPlatformWindow::mapToGlobal() instead of QWindow::mapToGlobal(). The latter operates on logical pixels. Task-number: QTBUG-55251 Change-Id: I789128a0a345d4113fced82ed1b215fe14044634 Reviewed-by: Friedemann Kleint --- src/plugins/platformthemes/gtk3/qgtk3menu.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp index 99407a21de1..cdd1abaf7d3 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp +++ b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp @@ -41,6 +41,7 @@ #include #include +#include #undef signals #include @@ -450,8 +451,9 @@ void QGtk3Menu::showPopup(const QWindow *parentWindow, const QRect &targetRect, m_targetPos = QPoint(targetRect.x(), targetRect.y() + targetRect.height()); - if (parentWindow) - m_targetPos = parentWindow->mapToGlobal(m_targetPos); + QPlatformWindow *pw = parentWindow ? parentWindow->handle() : nullptr; + if (pw) + m_targetPos = pw->mapToGlobal(m_targetPos); gtk_menu_popup(GTK_MENU(m_menu), NULL, NULL, qt_gtk_menu_position_func, this, 0, gtk_get_current_event_time()); } From efd5d7a837e7aa51ec64d9636932c0c83189f399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 5 Feb 2018 13:41:37 +0100 Subject: [PATCH 087/146] CoreText: Make sure to keep reference to data when cloning raw font engine QFontEngine::cloneWithSize() is used by QRawFont internally when switching a raw-font from one size to another using setPixelSize. For CoreText, we use a subclass of QCoreTextFontEngine to keep track of the QByteArray data of a raw-font, but failed to overload cloneWithSize, so we would lose the data whenever setPixelSize was called, resulting in missing text rendering in QtWebKit. We now retain the data as we should. Task-number: QTBUG-65923 Change-Id: I7d4186a3c32a61d48d1e9388e43f2792e8e46081 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../fontdatabases/mac/qfontengine_coretext.mm | 8 ++++ .../mac/qfontengine_coretext_p.h | 2 +- tests/auto/gui/text/qrawfont/tst_qrawfont.cpp | 39 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 66baf162d97..d96158d8f64 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -192,6 +192,14 @@ public: : QCoreTextFontEngine(font, def) , m_fontData(fontData) {} + QFontEngine *cloneWithSize(qreal pixelSize) const + { + QFontDef newFontDef = fontDef; + newFontDef.pixelSize = pixelSize; + newFontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + + return new QCoreTextRawFontEngine(cgFont, newFontDef, m_fontData); + } QByteArray m_fontData; }; diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h index 2986f0aaec6..d4c5e70cc12 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h @@ -125,7 +125,7 @@ public: static QFontEngine::GlyphFormat defaultGlyphFormat; static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); -private: +protected: void init(); QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool colorful, const QTransform &m); CTFontRef ctfont; diff --git a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp index 37f94d02783..373ad7fef96 100644 --- a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp @@ -93,6 +93,9 @@ private slots: void fallbackFontsOrder(); + void qtbug65923_partal_clone_data(); + void qtbug65923_partal_clone(); + private: QString testFont; QString testFontBoldItalic; @@ -1044,6 +1047,42 @@ void tst_QRawFont::fallbackFontsOrder() fontDatabase.removeApplicationFont(id); } +void tst_QRawFont::qtbug65923_partal_clone_data() +{ + QTest::addColumn("shouldClone"); + + QTest::newRow("Without cloning font engine") << false; + QTest::newRow("Cloning font engine") << true; +} + +void tst_QRawFont::qtbug65923_partal_clone() +{ + QFile file(testFont); + file.open(QIODevice::ReadOnly); + QByteArray fontData = file.readAll(); + + QRawFont outerFont; + + { + QRawFont innerFont(fontData, 16, QFont::PreferDefaultHinting); + + QFETCH(bool, shouldClone); + if (shouldClone) { + // This will trigger QFontEngine::cloneWithSize + innerFont.setPixelSize(innerFont.pixelSize() + 1); + } + + outerFont = innerFont; + } + + // This will detach if data is shared with the raw font. If the raw font has + // a naked reference to the data, without informing Qt of it via the ref count + // of the byte array, this will result in clearing 'live' data. + fontData.fill('\0'); + + QVERIFY(!outerFont.boundingRect(42).isEmpty()); +} + #endif // QT_NO_RAWFONT QTEST_MAIN(tst_QRawFont) From ce8e72d04012620d8243bfa38db087b5194b68c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 1 Feb 2018 12:17:48 +0100 Subject: [PATCH 088/146] Android: Defer initialization of logging rules until qApp construction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Android, we load the application library, and its dependencies (Qt), on Android's main thread (thread 0), and then spin up a secondary thread (thread 1), that we call main() on. If any QObject is constructed during loading of the application library or any of Qt's libraries, via static initializers or constructor functions, we will set QCoreApplicationPrivate::theMainThread to thread 0, which will confuse Qt later on when it's being run on thread 1, and will result in a warning during QCoreApplication construction: QApplication was not created in the main() thread This situation can easily lead to a crash as well. Unfortunately logging via qDebug/qCDebug and friends will trigger this too, as they internally use QObject. Fixing the root cause of this is under investigation, but for now we will partially revert fa2a653b3b934783 for Android. The effect is that any qCDebug with a "qt.*" category before qApp construction will turn into a no-op, like it was before fa2a653b3b934783. This patch does not cover the case of a regular qDebug, or a qCDebug with a non-Qt category. Those will still produce the same symptom, as before fa2a653b3b934783. Task-number: QTBUG-65863 Change-Id: I95675731d233244530d0a2a1c82a9578d5599775 Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Tor Arne Vestbø (cherry picked from commit 538b1b50764fb3a1898d425a7155319afbcf3b25) --- src/corelib/io/qloggingregistry.cpp | 10 ++++++++++ src/corelib/kernel/qcoreapplication.cpp | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp index b5f8e30b803..cd97268d716 100644 --- a/src/corelib/io/qloggingregistry.cpp +++ b/src/corelib/io/qloggingregistry.cpp @@ -44,6 +44,7 @@ #include #include #include +#include // We can't use the default macros because this would lead to recursion. // Instead let's define our own one that unconditionally logs... @@ -255,6 +256,15 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line) QLoggingRegistry::QLoggingRegistry() : categoryFilter(defaultCategoryFilter) { +#if defined(Q_OS_ANDROID) + // Unless QCoreApplication has been constructed we can't be sure that + // we are on Qt's main thread. If we did allow logging here, we would + // potentially set Qt's main thread to Android's thread 0, which would + // confuse Qt later when running main(). + if (!qApp) + return; +#endif + initializeRules(); // Init on first use } diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 12c2669f360..c8b130bbb93 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -776,6 +776,14 @@ void QCoreApplicationPrivate::init() if (!coreappdata()->applicationVersionSet) coreappdata()->applicationVersion = appVersion(); +#if defined(Q_OS_ANDROID) + // We've deferred initializing the logging registry due to not being + // able to guarantee that logging happened on the same thread as the + // Qt main thread, but now that the Qt main thread is set up, we can + // enable categorized logging. + QLoggingRegistry::instance()->initializeRules(); +#endif + #if QT_CONFIG(library) // Reset the lib paths, so that they will be recomputed, taking the availability of argv[0] // into account. If necessary, recompute right away and replay the manual changes on top of the From 36171af399e24095a0836e05a519a19e161a278e Mon Sep 17 00:00:00 2001 From: Adam Treat Date: Sat, 2 Dec 2017 10:36:12 -0500 Subject: [PATCH 089/146] Make use of our egl convenience code for QNX QPA This fixes various problems that occur because the current egl context assumes OpenGL ES 2.0 and does not support newer versions of ES. Task-number: QTBUG-64306 Change-Id: I81466ba5cf028b47ca5a2ebcdc702167aff655a2 Reviewed-by: James McDonnell --- src/plugins/platforms/qnx/qnx.pro | 4 +- src/plugins/platforms/qnx/qqnxeglwindow.cpp | 130 ++++++----- src/plugins/platforms/qnx/qqnxeglwindow.h | 16 +- src/plugins/platforms/qnx/qqnxglcontext.cpp | 212 ++---------------- src/plugins/platforms/qnx/qqnxglcontext.h | 30 +-- src/plugins/platforms/qnx/qqnxintegration.cpp | 53 ++++- .../platforms/qnx/qqnxnativeinterface.cpp | 2 +- src/plugins/platforms/qnx/qqnxscreen.h | 10 +- src/plugins/platforms/qnx/qqnxwindow.h | 3 +- 9 files changed, 162 insertions(+), 298 deletions(-) diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 15d33200e5f..96bfa1dd192 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -71,14 +71,14 @@ HEADERS = main.h \ LIBS += -lscreen -qtConfig(opengles2) { +qtConfig(egl) { SOURCES += qqnxglcontext.cpp \ qqnxeglwindow.cpp HEADERS += qqnxglcontext.h \ qqnxeglwindow.h - QMAKE_USE += opengl_es2 egl + QMAKE_USE += egl } qtConfig(qqnx_pps) { diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp index 33ce0f924c2..48766fc4358 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp @@ -56,18 +56,12 @@ QT_BEGIN_NAMESPACE QQnxEglWindow::QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow) : QQnxWindow(window, context, needRootWindow), - m_platformOpenGLContext(0), m_newSurfaceRequested(true), + m_eglDisplay(EGL_NO_DISPLAY), m_eglSurface(EGL_NO_SURFACE) { initWindow(); - // Set window usage - const int val = SCREEN_USAGE_OPENGL_ES2; - const int result = screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_USAGE, &val); - if (Q_UNLIKELY(result != 0)) - qFatal("QQnxEglWindow: failed to set window alpha usage, errno=%d", errno); - m_requestedBufferSize = shouldMakeFullScreen() ? screen()->geometry().size() : window->geometry().size(); } @@ -77,14 +71,58 @@ QQnxEglWindow::~QQnxEglWindow() destroyEGLSurface(); } -void QQnxEglWindow::createEGLSurface() +bool QQnxEglWindow::isInitialized() const { + return m_eglSurface != EGL_NO_SURFACE; +} + +void QQnxEglWindow::ensureInitialized(QQnxGLContext* context) +{ + if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { + const QMutexLocker locker(&m_mutex); // Set geomety must not reset the requestedBufferSize till + // the surface is created + + if (m_requestedBufferSize != bufferSize() || m_eglSurface == EGL_NO_SURFACE) { + if (m_eglSurface != EGL_NO_SURFACE) { + context->doneCurrent(); + destroyEGLSurface(); + } + createEGLSurface(context); + } else { + // Must've been a sequence of unprocessed changes returning us to the original size. + resetBuffers(); + } + } +} + +void QQnxEglWindow::createEGLSurface(QQnxGLContext *context) +{ + if (context->format().renderableType() != QSurfaceFormat::OpenGLES) { + qFatal("QQnxEglWindow: renderable type is not OpenGLES"); + return; + } + + // Set window usage + int usage = SCREEN_USAGE_OPENGL_ES2; +#if _SCREEN_VERSION >= _SCREEN_MAKE_VERSION(1, 0, 0) + if (context->format().majorVersion() == 3) + usage |= SCREEN_USAGE_OPENGL_ES3; +#endif + + const int result = screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_USAGE, &usage); + if (Q_UNLIKELY(result != 0)) + qFatal("QQnxEglWindow: failed to set window usage, errno=%d", errno); + if (!m_requestedBufferSize.isValid()) { qWarning("QQNX: Trying to create 0 size EGL surface. " "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); return; } + m_eglDisplay = context->eglDisplay(); + m_eglConfig = context->eglConfig(); + m_format = context->format(); + // update the window's buffers before we create the EGL surface setBufferSize(m_requestedBufferSize); @@ -94,24 +132,27 @@ void QQnxEglWindow::createEGLSurface() EGL_NONE }; - qEglWindowDebug() << "Creating EGL surface" << platformOpenGLContext()->getEglDisplay() - << platformOpenGLContext()->getEglConfig(); + qEglWindowDebug() << "Creating EGL surface from" << this << context + << window()->surfaceType() << window()->type(); // Create EGL surface - m_eglSurface = eglCreateWindowSurface(platformOpenGLContext()->getEglDisplay(), - platformOpenGLContext()->getEglConfig(), - (EGLNativeWindowType) nativeHandle(), eglSurfaceAttrs); - if (m_eglSurface == EGL_NO_SURFACE) { - const EGLenum error = QQnxGLContext::checkEGLError("eglCreateWindowSurface"); - qWarning("QQNX: failed to create EGL surface, err=%d", error); - } + EGLSurface eglSurface = eglCreateWindowSurface( + m_eglDisplay, + m_eglConfig, + (EGLNativeWindowType) nativeHandle(), + eglSurfaceAttrs); + + if (eglSurface == EGL_NO_SURFACE) + qWarning("QQNX: failed to create EGL surface, err=%d", eglGetError()); + + m_eglSurface = eglSurface; } void QQnxEglWindow::destroyEGLSurface() { // Destroy EGL surface if it exists if (m_eglSurface != EGL_NO_SURFACE) { - EGLBoolean eglResult = eglDestroySurface(platformOpenGLContext()->getEglDisplay(), m_eglSurface); + EGLBoolean eglResult = eglDestroySurface(m_eglDisplay, m_eglSurface); if (Q_UNLIKELY(eglResult != EGL_TRUE)) qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); } @@ -119,40 +160,8 @@ void QQnxEglWindow::destroyEGLSurface() m_eglSurface = EGL_NO_SURFACE; } -void QQnxEglWindow::swapEGLBuffers() +EGLSurface QQnxEglWindow::surface() const { - qEglWindowDebug(); - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Post EGL surface to window - eglResult = eglSwapBuffers(m_platformOpenGLContext->getEglDisplay(), m_eglSurface); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); - - windowPosted(); -} - -EGLSurface QQnxEglWindow::getSurface() -{ - if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { - const QMutexLocker locker(&m_mutex); //Set geomety must not reset the requestedBufferSize till - //the surface is created - - if ((m_requestedBufferSize != bufferSize()) || (m_eglSurface == EGL_NO_SURFACE)) { - if (m_eglSurface != EGL_NO_SURFACE) { - platformOpenGLContext()->doneCurrent(); - destroyEGLSurface(); - } - createEGLSurface(); - } else { - // Must've been a sequence of unprocessed changes returning us to the original size. - resetBuffers(); - } - } - return m_eglSurface; } @@ -169,35 +178,24 @@ void QQnxEglWindow::setGeometry(const QRect &rect) // that test. const QMutexLocker locker(&m_mutex); m_requestedBufferSize = newGeometry.size(); - if (m_platformOpenGLContext != 0 && bufferSize() != newGeometry.size()) + if (isInitialized() && bufferSize() != newGeometry.size()) m_newSurfaceRequested.testAndSetRelease(false, true); } QQnxWindow::setGeometry(newGeometry); } -void QQnxEglWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext) -{ - // This function does not take ownership of the platform gl context. - // It is owned by the frontend QOpenGLContext - m_platformOpenGLContext = platformOpenGLContext; -} - int QQnxEglWindow::pixelFormat() const { - if (!m_platformOpenGLContext) //The platform GL context was not set yet - return -1; - - const QSurfaceFormat format = m_platformOpenGLContext->format(); // Extract size of color channels from window format - const int redSize = format.redBufferSize(); + const int redSize = m_format.redBufferSize(); if (Q_UNLIKELY(redSize == -1)) qFatal("QQnxWindow: red size not defined"); - const int greenSize = format.greenBufferSize(); + const int greenSize = m_format.greenBufferSize(); if (Q_UNLIKELY(greenSize == -1)) qFatal("QQnxWindow: green size not defined"); - const int blueSize = format.blueBufferSize(); + const int blueSize = m_format.blueBufferSize(); if (Q_UNLIKELY(blueSize == -1)) qFatal("QQnxWindow: blue size not defined"); diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h index 183be11ddcf..3a3840f13c2 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.h +++ b/src/plugins/platforms/qnx/qqnxeglwindow.h @@ -53,13 +53,10 @@ public: QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow); ~QQnxEglWindow(); - void createEGLSurface(); - void destroyEGLSurface(); - void swapEGLBuffers(); - EGLSurface getSurface(); + EGLSurface surface() const; - void setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext); - QQnxGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; } + bool isInitialized() const; + void ensureInitialized(QQnxGLContext *context); void setGeometry(const QRect &rect) override; @@ -68,6 +65,9 @@ protected: void resetBuffers() override; private: + void createEGLSurface(QQnxGLContext *context); + void destroyEGLSurface(); + QSize m_requestedBufferSize; // This mutex is used to protect access to the m_requestedBufferSize @@ -78,9 +78,11 @@ private: // QQnxGLContext::makeCurrent() mutable QMutex m_mutex; - QQnxGLContext *m_platformOpenGLContext; QAtomicInt m_newSurfaceRequested; + EGLDisplay m_eglDisplay; + EGLConfig m_eglConfig; EGLSurface m_eglSurface; + QSurfaceFormat m_format; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index d35a4f0bba4..d4493943e23 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -59,117 +59,13 @@ QT_BEGIN_NAMESPACE EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY; -QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext) - : QPlatformOpenGLContext(), - m_glContext(glContext), - m_currentEglSurface(EGL_NO_SURFACE) +QQnxGLContext::QQnxGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : QEGLPlatformContext(format, share, ms_eglDisplay) { - qGLContextDebug(); - QSurfaceFormat format = m_glContext->format(); - - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Get colour channel sizes from window format - int alphaSize = format.alphaBufferSize(); - int redSize = format.redBufferSize(); - int greenSize = format.greenBufferSize(); - int blueSize = format.blueBufferSize(); - - // Check if all channels are don't care - if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) { - // Set colour channels based on depth of window's screen - QQnxScreen *screen = static_cast(glContext->screen()->handle()); - int depth = screen->depth(); - if (depth == 32) { - // SCREEN_FORMAT_RGBA8888 - alphaSize = 8; - redSize = 8; - greenSize = 8; - blueSize = 8; - } else { - // SCREEN_FORMAT_RGB565 - alphaSize = 0; - redSize = 5; - greenSize = 6; - blueSize = 5; - } - } else { - // Choose best match based on supported pixel formats - if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) { - // SCREEN_FORMAT_RGB565 - alphaSize = 0; - redSize = 5; - greenSize = 6; - blueSize = 5; - } else { - // SCREEN_FORMAT_RGBA8888 - alphaSize = 8; - redSize = 8; - greenSize = 8; - blueSize = 8; - } - } - - // Update colour channel sizes in window format - format.setAlphaBufferSize(alphaSize); - format.setRedBufferSize(redSize); - format.setGreenBufferSize(greenSize); - format.setBlueBufferSize(blueSize); - - // Select EGL config based on requested window format - m_eglConfig = q_configFromGLFormat(ms_eglDisplay, format); - if (Q_UNLIKELY(m_eglConfig == 0)) - qFatal("QQnxGLContext: failed to find EGL config"); - - QQnxGLContext *glShareContext = static_cast(m_glContext->shareHandle()); - m_eglShareContext = glShareContext ? glShareContext->m_eglContext : EGL_NO_CONTEXT; - - m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, m_eglShareContext, - contextAttrs(format)); - if (Q_UNLIKELY(m_eglContext == EGL_NO_CONTEXT)) { - checkEGLError("eglCreateContext"); - qFatal("QQnxGLContext: failed to create EGL context, err=%d", eglGetError()); - } - - // Query/cache window format of selected EGL config - m_windowFormat = q_glFormatFromConfig(ms_eglDisplay, m_eglConfig); } QQnxGLContext::~QQnxGLContext() { - qGLContextDebug(); - - // Cleanup EGL context if it exists - if (m_eglContext != EGL_NO_CONTEXT) - eglDestroyContext(ms_eglDisplay, m_eglContext); -} - -EGLenum QQnxGLContext::checkEGLError(const char *msg) -{ - static const char *errmsg[] = - { - "EGL function succeeded", - "EGL is not initialized, or could not be initialized, for the specified display", - "EGL cannot access a requested resource", - "EGL failed to allocate resources for the requested operation", - "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", - "EGLConfig argument does not name a valid EGLConfig", - "EGLContext argument does not name a valid EGLContext", - "EGL current surface of the calling thread is no longer valid", - "EGLDisplay argument does not name a valid EGLDisplay", - "EGL arguments are inconsistent", - "EGLNativePixmapType argument does not refer to a valid native pixmap", - "EGLNativeWindowType argument does not refer to a valid native window", - "EGL one or more argument values are invalid", - "EGLSurface argument does not name a valid surface configured for rendering", - "EGL power management event has occurred", - }; - EGLenum error = eglGetError(); - fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); - return error; } void QQnxGLContext::initializeContext() @@ -178,16 +74,12 @@ void QQnxGLContext::initializeContext() // Initialize connection to EGL ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (Q_UNLIKELY(ms_eglDisplay == EGL_NO_DISPLAY)) { - checkEGLError("eglGetDisplay"); - qFatal("QQnxGLContext: failed to obtain EGL display"); - } + if (Q_UNLIKELY(ms_eglDisplay == EGL_NO_DISPLAY)) + qFatal("QQnxGLContext: failed to obtain EGL display: %x", eglGetError()); EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) { - checkEGLError("eglInitialize"); + if (Q_UNLIKELY(eglResult != EGL_TRUE)) qFatal("QQnxGLContext: failed to initialize EGL display, err=%d", eglGetError()); - } } void QQnxGLContext::shutdownContext() @@ -198,98 +90,32 @@ void QQnxGLContext::shutdownContext() eglTerminate(ms_eglDisplay); } +EGLSurface QQnxGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +{ + QQnxEglWindow *window = static_cast(surface); + window->ensureInitialized(this); + return window->surface(); +} + bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) { qGLContextDebug(); - - Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface); - - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQnxGLContext: failed to set EGL API, err=%d", eglGetError()); - - QQnxEglWindow *platformWindow = dynamic_cast(surface); - if (!platformWindow) - return false; - - platformWindow->setPlatformOpenGLContext(this); - - if (m_currentEglSurface == EGL_NO_SURFACE || m_currentEglSurface != platformWindow->getSurface()) { - m_currentEglSurface = platformWindow->getSurface(); - doneCurrent(); - } - - eglResult = eglMakeCurrent(ms_eglDisplay, m_currentEglSurface, m_currentEglSurface, m_eglContext); - if (eglResult != EGL_TRUE) { - checkEGLError("eglMakeCurrent"); - qWarning("QQNX: failed to set current EGL context, err=%d", eglGetError()); - return false; - } - return (eglResult == EGL_TRUE); -} - -void QQnxGLContext::doneCurrent() -{ - qGLContextDebug(); - - // set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // clear curent EGL context and unbind EGL surface - eglResult = eglMakeCurrent(ms_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to clear current EGL context, err=%d", eglGetError()); + return QEGLPlatformContext::makeCurrent(surface); } void QQnxGLContext::swapBuffers(QPlatformSurface *surface) { qGLContextDebug(); - QQnxEglWindow *platformWindow = dynamic_cast(surface); - if (!platformWindow) - return; - platformWindow->swapEGLBuffers(); + QEGLPlatformContext::swapBuffers(surface); + + QQnxEglWindow *platformWindow = static_cast(surface); + platformWindow->windowPosted(); } -QFunctionPointer QQnxGLContext::getProcAddress(const char *procName) +void QQnxGLContext::doneCurrent() { - qGLContextDebug(); - - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Lookup EGL extension function pointer - QFunctionPointer result = static_cast(eglGetProcAddress(procName)); - if (!result) - result = reinterpret_cast(dlsym(RTLD_DEFAULT, procName)); - return result; -} - -bool QQnxGLContext::isSharing() const -{ - return m_eglShareContext != EGL_NO_CONTEXT; -} - -EGLDisplay QQnxGLContext::getEglDisplay() { - return ms_eglDisplay; -} - -EGLint *QQnxGLContext::contextAttrs(const QSurfaceFormat &format) -{ - qGLContextDebug(); - - // Choose EGL settings based on OpenGL version -#if defined(QT_OPENGL_ES_2) - static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, format.version().first, EGL_NONE }; - return attrs; -#else - return 0; -#endif + QEGLPlatformContext::doneCurrent(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h index 6e5408e8bf0..19179a80e25 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.h +++ b/src/plugins/platforms/qnx/qqnxglcontext.h @@ -46,49 +46,31 @@ #include #include +#include QT_BEGIN_NAMESPACE class QQnxWindow; -class QQnxGLContext : public QPlatformOpenGLContext +class QQnxGLContext : public QEGLPlatformContext { public: - QQnxGLContext(QOpenGLContext *glContext); + QQnxGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share); virtual ~QQnxGLContext(); - static EGLenum checkEGLError(const char *msg); - static void initializeContext(); static void shutdownContext(); - void requestSurfaceChange(); - bool makeCurrent(QPlatformSurface *surface) override; - void doneCurrent() override; void swapBuffers(QPlatformSurface *surface) override; - QFunctionPointer getProcAddress(const char *procName) override; + void doneCurrent() override; - virtual QSurfaceFormat format() const override { return m_windowFormat; } - bool isSharing() const override; - - static EGLDisplay getEglDisplay(); - EGLConfig getEglConfig() const { return m_eglConfig;} - EGLContext getEglContext() const { return m_eglContext; } +protected: + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override; private: //Can be static because different displays returne the same handle static EGLDisplay ms_eglDisplay; - - QSurfaceFormat m_windowFormat; - QOpenGLContext *m_glContext; - - EGLConfig m_eglConfig; - EGLContext m_eglContext; - EGLContext m_eglShareContext; - EGLSurface m_currentEglSurface; - - static EGLint *contextAttrs(const QSurfaceFormat &format); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index 072510e0528..bffe7ee34bd 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -313,7 +313,58 @@ QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *wind QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { qIntegrationDebug(); - return new QQnxGLContext(context); + + // Get color channel sizes from window format + QSurfaceFormat format = context->format(); + int alphaSize = format.alphaBufferSize(); + int redSize = format.redBufferSize(); + int greenSize = format.greenBufferSize(); + int blueSize = format.blueBufferSize(); + + // Check if all channels are don't care + if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) { + // Set color channels based on depth of window's screen + QQnxScreen *screen = static_cast(context->screen()->handle()); + int depth = screen->depth(); + if (depth == 32) { + // SCREEN_FORMAT_RGBA8888 + alphaSize = 8; + redSize = 8; + greenSize = 8; + blueSize = 8; + } else { + // SCREEN_FORMAT_RGB565 + alphaSize = 0; + redSize = 5; + greenSize = 6; + blueSize = 5; + } + } else { + // Choose best match based on supported pixel formats + if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) { + // SCREEN_FORMAT_RGB565 + alphaSize = 0; + redSize = 5; + greenSize = 6; + blueSize = 5; + } else { + // SCREEN_FORMAT_RGBA8888 + alphaSize = 8; + redSize = 8; + greenSize = 8; + blueSize = 8; + } + } + + // Update color channel sizes in window format + format.setAlphaBufferSize(alphaSize); + format.setRedBufferSize(redSize); + format.setGreenBufferSize(greenSize); + format.setBlueBufferSize(blueSize); + context->setFormat(format); + + QQnxGLContext *ctx = new QQnxGLContext(context->format(), context->shareHandle()); + return ctx; } #endif diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp index 468fe9cd91b..3eebb9c7424 100644 --- a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp +++ b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp @@ -98,7 +98,7 @@ void *QQnxNativeInterface::nativeResourceForIntegration(const QByteArray &resour void *QQnxNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { if (resource == "eglcontext" && context) - return static_cast(context->handle())->getEglContext(); + return static_cast(context->handle())->eglContext(); return 0; } diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index 8a498434aaa..a6d5623d049 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -49,10 +49,14 @@ #include -// For pre-7.0 SDPs, map some screen property names to the old +#if !defined(_SCREEN_VERSION) +#define _SCREEN_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) +#define _SCREEN_VERSION _SCREEN_MAKE_VERSION(0, 0, 0) +#endif + +// For pre-1.0.0 screen, map some screen property names to the old // names. -#include -#if _NTO_VERSION < 700 +#if _SCREEN_VERSION < _SCREEN_MAKE_VERSION(1, 0, 0) const int SCREEN_PROPERTY_FLAGS = SCREEN_PROPERTY_KEY_FLAGS; const int SCREEN_PROPERTY_FOCUS = SCREEN_PROPERTY_KEYBOARD_FOCUS; const int SCREEN_PROPERTY_MODIFIERS = SCREEN_PROPERTY_KEY_MODIFIERS; diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index e248e04462d..223ea6e3496 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -112,12 +112,13 @@ public: bool shouldMakeFullScreen() const; + void windowPosted(); + protected: virtual int pixelFormat() const = 0; virtual void resetBuffers() = 0; void initWindow(); - void windowPosted(); screen_context_t m_screenContext; From f1d227bceb5cbf58adbc107aa2e2f83df401d71e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 7 Feb 2018 20:20:34 +0100 Subject: [PATCH 090/146] Bump version Change-Id: I668f25fddaf597db4b3b5537379acd3a2f4c4f8f --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 135d1f7de14..57938d9989f 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -4,4 +4,4 @@ CONFIG += warning_clean QT_SOURCE_TREE = $$PWD QT_BUILD_TREE = $$shadowed($$PWD) -MODULE_VERSION = 5.9.4 +MODULE_VERSION = 5.9.5 From b624cdac21c7fd673c5c9e73be158f3b5fb79bc5 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 8 Feb 2018 17:14:38 +0100 Subject: [PATCH 091/146] tst_QSharedPointer: Fix termination of external processes on Windows Timeouts with subsequent failures to delete the temporary directories have been observed in COIN. Previously, QProcess:terminate() was used to end the processes, which does not have any effect on console processes on Windows. Add a helper function which resorts to kill() on failure to terminate(). Change-Id: I05539d1703280d34b392f2e8ff8565b9a04d703c Reviewed-by: Thiago Macieira --- .../tools/qsharedpointer/externaltests.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp index 62dd33131bc..3e1668522ea 100644 --- a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp +++ b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #ifndef DEFAULT_MAKESPEC # error DEFAULT_MAKESPEC not defined @@ -69,6 +70,16 @@ static QString makespec() QT_BEGIN_NAMESPACE namespace QTest { #if QT_CONFIG(process) + static void ensureStopped(QProcess &process) + { + if (process.state() == QProcess::Running) { + process.terminate(); + QThread::msleep(20); + if (process.state() == QProcess::Running) + process.kill(); + } + } + class QExternalProcess: public QProcess { protected: @@ -594,7 +605,7 @@ namespace QTest { ok = qmake.waitForFinished(); exitCode = qmake.exitCode(); if (!ok) - qmake.terminate(); + QTest::ensureStopped(qmake); std_out += qmake.readAllStandardOutput(); std_err += qmake.readAllStandardError(); @@ -661,7 +672,7 @@ namespace QTest { make.closeWriteChannel(); bool ok = make.waitForFinished(channelMode == QProcess::ForwardedChannels ? -1 : 60000); if (!ok) - make.terminate(); + QTest::ensureStopped(make); exitCode = make.exitCode(); std_out += make.readAllStandardOutput(); std_err += make.readAllStandardError(); From 83b0abf928af6cd9f301e3367c439eca22aab323 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Tue, 30 Jan 2018 00:32:36 +0100 Subject: [PATCH 092/146] Use the right attribute when checking if shortcuts are shown Change-Id: I784965dda64551e6093af817881aa6472d2cc226 Reviewed-by: Jake Petroules Reviewed-by: Gabriel de Dietrich --- src/widgets/kernel/qaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp index 853e27cd6e5..a48eb900486 100644 --- a/src/widgets/kernel/qaction.cpp +++ b/src/widgets/kernel/qaction.cpp @@ -1332,7 +1332,7 @@ bool QAction::isShortcutVisibleInContextMenu() const { Q_D(const QAction); if (d->shortcutVisibleInContextMenu == -1) { - if (QApplication::instance()->testAttribute(Qt::AA_DontShowIconsInMenus)) + if (QApplication::instance()->testAttribute(Qt::AA_DontShowShortcutsInContextMenus)) return false; return qApp->styleHints()->showShortcutsInContextMenus(); } From c48f4bde0044bd5b23af231f3639d0779ecbdb03 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 1 Feb 2018 20:59:58 +0100 Subject: [PATCH 093/146] Set the ellipseDiameters back to the original size in QGraphicsView When calling setSceneRect() on a QTouchPoint it will cause the ellipseDiameters to be changed, whereas this should not be affected by the scene rectangle as it should be in logical pixels. Also add a manual test for visually checking the ellipse diameters on various devices. Change-Id: I1ee9207cb1a63cfef33fe904594c73aba221af5c Reviewed-by: Shawn Rutledge --- src/widgets/graphicsview/qgraphicsview.cpp | 6 +- .../qgraphicsscene/tst_qgraphicsscene.cpp | 76 ++++++++ tests/manual/touchGraphicsItem/main.cpp | 163 ++++++++++++++++++ .../touchGraphicsItem/touchGraphicsItem.pro | 5 + 4 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 tests/manual/touchGraphicsItem/main.cpp create mode 100644 tests/manual/touchGraphicsItem/touchGraphicsItem.pro diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index 1cc8543fddc..0c847b899e3 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -313,13 +313,15 @@ void QGraphicsViewPrivate::translateTouchEvent(QGraphicsViewPrivate *d, QTouchEv QList touchPoints = touchEvent->touchPoints(); for (int i = 0; i < touchPoints.count(); ++i) { QTouchEvent::TouchPoint &touchPoint = touchPoints[i]; + const QSizeF ellipseDiameters = touchPoint.ellipseDiameters(); // the scene will set the item local pos, startPos, lastPos, and rect before delivering to // an item, but for now those functions are returning the view's local coordinates - touchPoint.setSceneRect(d->mapToScene(touchPoint.rect())); + touchPoint.setScenePos(d->mapToScene(touchPoint.pos())); touchPoint.setStartScenePos(d->mapToScene(touchPoint.startPos())); touchPoint.setLastScenePos(d->mapToScene(touchPoint.lastPos())); + touchPoint.setEllipseDiameters(ellipseDiameters); - // screenPos, startScreenPos, lastScreenPos, and screenRect are already set + // screenPos, startScreenPos, and lastScreenPos are already set } touchEvent->setTouchPoints(touchPoints); diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp index bfdb540c2b2..e7cf8f17a2a 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp @@ -254,6 +254,7 @@ private slots: void zeroScale(); void focusItemChangedSignal(); void minimumRenderSize(); + void checkTouchPointsEllipseDiameters(); // task specific tests below me void task139710_bspTreeCrash(); @@ -4764,6 +4765,81 @@ void tst_QGraphicsScene::minimumRenderSize() QVERIFY(smallChild->repaints > smallerGrandChild->repaints); } +class TouchItem : public QGraphicsRectItem +{ +public: + TouchItem() : QGraphicsRectItem(QRectF(-10, -10, 20, 20)), + seenTouch(false) + { + setAcceptTouchEvents(true); + setFlag(QGraphicsItem::ItemIgnoresTransformations); + } + bool seenTouch; + QList touchPoints; +protected: + bool sceneEvent(QEvent *event) override + { + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + seenTouch = true; + touchPoints = static_cast(event)->touchPoints(); + event->accept(); + return true; + default: + break; + } + return QGraphicsRectItem::sceneEvent(event); + } +}; + +void tst_QGraphicsScene::checkTouchPointsEllipseDiameters() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + scene.setSceneRect(1, 1, 198, 198); + view.scale(1.5, 1.5); + view.setFocus(); + TouchItem *rect = new TouchItem; + scene.addItem(rect); + view.show(); + QApplication::setActiveWindow(&view); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + const QSizeF ellipseDiameters(10.0, 10.0); + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(rect->mapToScene(rect->boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setEllipseDiameters(ellipseDiameters); + + QList touchPoints = { touchPoint }; + + QTouchDevice *testDevice = QTest::createTouchDevice(QTouchDevice::TouchPad); + QTouchEvent touchEvent(QEvent::TouchBegin, + testDevice, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + QApplication::sendEvent(view.viewport(), &touchEvent); + QVERIFY(rect->seenTouch); + QVERIFY(rect->touchPoints.size() == 1); + QCOMPARE(ellipseDiameters, rect->touchPoints.first().ellipseDiameters()); + + rect->seenTouch = false; + rect->touchPoints.clear(); + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + testDevice, + Qt::NoModifier, + Qt::TouchPointMoved, + touchPoints); + QApplication::sendEvent(view.viewport(), &touchEvent); + QVERIFY(rect->seenTouch); + QVERIFY(rect->touchPoints.size() == 1); + QCOMPARE(ellipseDiameters, rect->touchPoints.first().ellipseDiameters()); +} + void tst_QGraphicsScene::taskQTBUG_15977_renderWithDeviceCoordinateCache() { QGraphicsScene scene; diff --git a/tests/manual/touchGraphicsItem/main.cpp b/tests/manual/touchGraphicsItem/main.cpp new file mode 100644 index 00000000000..7afadc7edd7 --- /dev/null +++ b/tests/manual/touchGraphicsItem/main.cpp @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +class TouchableItem : public QGraphicsRectItem +{ +public: + TouchableItem() : QGraphicsRectItem(50, 50, 400, 400) + { + setBrush(Qt::yellow); + setAcceptTouchEvents(true); + } +protected: + bool sceneEvent(QEvent *e) + { + const bool ret = QGraphicsRectItem::sceneEvent(e); + switch (e->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + { + QTouchEvent *te = static_cast(e); + for (const QTouchEvent::TouchPoint &tp : te->touchPoints()) { + QGraphicsEllipseItem *diameterItem = nullptr; + QSizeF ellipse = tp.ellipseDiameters(); + if (ellipse.isNull()) { + ellipse = QSizeF(5, 5); + } else { + diameterItem = new QGraphicsEllipseItem(QRectF(tp.pos().x() - ellipse.width() / 2, tp.pos().y() - ellipse.height() / 2, + ellipse.width(), ellipse.height()), this); + diameterItem->setPen(QPen(Qt::red)); + diameterItem->setBrush(QBrush(Qt::red)); + if (ellipse.width() > qreal(2) && ellipse.height() > qreal(2)) + ellipse.scale(ellipse.width() - 2, ellipse.height() - 2, Qt::IgnoreAspectRatio); + } + QGraphicsItem *parent = diameterItem ? static_cast(diameterItem) : static_cast(this); + QGraphicsEllipseItem *ellipseItem = new QGraphicsEllipseItem(QRectF(tp.pos().x() - ellipse.width() / 2, + tp.pos().y() - ellipse.height() / 2, + ellipse.width(), ellipse.height()), parent); + ellipseItem->setPen(QPen(Qt::blue)); + ellipseItem->setBrush(QBrush(Qt::blue)); + } + te->accept(); + return true; + } + default: + break; + } + return ret; + } +}; + +int main(int argc, char **argv) +{ + QApplication a(argc, argv); + QMainWindow mw; + QWidget *w = new QWidget; + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(new QLabel("The blue ellipses should indicate touch point contact patches")); + qDebug() << "Touch devices:"; + for (const QTouchDevice *device : QTouchDevice::devices()) { + QString result; + QTextStream str(&result); + str << (device->type() == QTouchDevice::TouchScreen ? "TouchScreen" : "TouchPad") + << " \"" << device->name() << "\", max " << device->maximumTouchPoints() + << " touch points, capabilities:"; + const QTouchDevice::Capabilities capabilities = device->capabilities(); + if (capabilities & QTouchDevice::Position) + str << " Position"; + if (capabilities & QTouchDevice::Area) + str << " Area"; + if (capabilities & QTouchDevice::Pressure) + str << " Pressure"; + if (capabilities & QTouchDevice::Velocity) + str << " Velocity"; + if (capabilities & QTouchDevice::RawPositions) + str << " RawPositions"; + if (capabilities & QTouchDevice::NormalizedPosition) + str << " NormalizedPosition"; + if (capabilities & QTouchDevice::MouseEmulation) + str << " MouseEmulation"; + vbox->addWidget(new QLabel(result)); + qDebug() << " " << result; + } + QGraphicsView *view = new QGraphicsView; + view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents); + QGraphicsScene *scene = new QGraphicsScene(0, 0, 500, 500); + TouchableItem *touchableItem = new TouchableItem; + scene->addItem(touchableItem); + view->setScene(scene); + vbox->addWidget(view); + w->setLayout(vbox); + mw.setCentralWidget(w); + QMenu *menu = mw.menuBar()->addMenu("Menu"); + QAction *clear = new QAction("Clear"); + QObject::connect(clear, &QAction::triggered, [=]() { + qDeleteAll(touchableItem->childItems()); + }); + menu->addAction(clear); + QAction *ignoreTransform = new QAction("Ignore transformations"); + QObject::connect(ignoreTransform, &QAction::triggered, [=]() { + view->scale(1.5, 1.5); + touchableItem->setFlag(QGraphicsItem::ItemIgnoresTransformations); + }); + menu->addAction(ignoreTransform); + QAction *quit = new QAction("Quit"); + quit->setShortcut(QKeySequence::Quit); + QObject::connect(quit, &QAction::triggered, &QApplication::quit); + menu->addAction(quit); + mw.show(); + + return a.exec(); +} + + diff --git a/tests/manual/touchGraphicsItem/touchGraphicsItem.pro b/tests/manual/touchGraphicsItem/touchGraphicsItem.pro new file mode 100644 index 00000000000..67799ce9c4e --- /dev/null +++ b/tests/manual/touchGraphicsItem/touchGraphicsItem.pro @@ -0,0 +1,5 @@ +QT+=widgets +TEMPLATE = app +TARGET = touchGraphicsItem +INCLUDEPATH += . +SOURCES += main.cpp From 44402f50754e9ca260f9cbe8d5e68d899342544d Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Tue, 6 Feb 2018 15:12:22 +0200 Subject: [PATCH 094/146] Skip tst_QDBusAbstractAdaptor peer tests The peer Tests for QDBusAbstractAdaptor are so flaky that it's very difficult to get any commits through to qtbase. Task-number: QTBUG-66216 Change-Id: I8da80f71aa832e683f72129cb2d4785425d39c00 Reviewed-by: Ville Voutilainen Reviewed-by: Sami Nurmenniemi Reviewed-by: Friedemann Kleint --- .../tst_qdbusabstractadaptor.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp b/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp index 20cd8caad34..80f22ad8674 100644 --- a/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp +++ b/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp @@ -1083,6 +1083,7 @@ void tst_QDBusAbstractAdaptor::methodCallsPeer_data() void tst_QDBusAbstractAdaptor::methodCallsPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); if (QSysInfo::productType().compare("opensuse", Qt::CaseInsensitive) == 0 && QSysInfo::productVersion() == QLatin1String("42.1") && qgetenv("QTEST_ENVIRONMENT").split(' ').contains("ci")) { @@ -1150,6 +1151,7 @@ void tst_QDBusAbstractAdaptor::methodCallsPeer() void tst_QDBusAbstractAdaptor::methodCallScriptablePeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1169,6 +1171,7 @@ void tst_QDBusAbstractAdaptor::signalEmissionsPeer_data() void tst_QDBusAbstractAdaptor::signalEmissionsPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QFETCH(QString, interface); QFETCH(QString, name); QFETCH(QVariant, parameter); @@ -1233,6 +1236,7 @@ void tst_QDBusAbstractAdaptor::signalEmissionsPeer() void tst_QDBusAbstractAdaptor::sameSignalDifferentPathsPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1261,6 +1265,7 @@ void tst_QDBusAbstractAdaptor::sameSignalDifferentPathsPeer() void tst_QDBusAbstractAdaptor::sameObjectDifferentPathsPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1283,6 +1288,7 @@ void tst_QDBusAbstractAdaptor::sameObjectDifferentPathsPeer() void tst_QDBusAbstractAdaptor::scriptableSignalOrNotPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer");; QVERIFY(con.isConnected()); @@ -1356,6 +1362,7 @@ void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer_data() void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1407,6 +1414,7 @@ void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer() void tst_QDBusAbstractAdaptor::readPropertiesPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1431,6 +1439,7 @@ void tst_QDBusAbstractAdaptor::readPropertiesPeer() void tst_QDBusAbstractAdaptor::readPropertiesInvalidInterfacePeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1451,6 +1460,7 @@ void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer_data() void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1481,6 +1491,7 @@ void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer() void tst_QDBusAbstractAdaptor::readAllPropertiesPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1507,6 +1518,7 @@ void tst_QDBusAbstractAdaptor::readAllPropertiesPeer() void tst_QDBusAbstractAdaptor::readAllPropertiesInvalidInterfacePeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1572,6 +1584,7 @@ void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer() void tst_QDBusAbstractAdaptor::writePropertiesPeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); @@ -1883,6 +1896,7 @@ void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValue() void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValuePeer() { + QSKIP("Test is currently too flaky (QTBUG-66223)"); QDBusConnection con("peer"); QVERIFY(con.isConnected()); From 9ac09dcc6848ef04698ec1ec33c176c433309c68 Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Tue, 6 Feb 2018 13:05:15 +0200 Subject: [PATCH 095/146] Blacklist flaky cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-66216 Change-Id: Iae973c1224c940752e2c3162d8c64539966ff7ac Reviewed-by: Tony Sarajärvi Reviewed-by: Timur Pocheptsov --- tests/auto/network/access/qnetworkreply/BLACKLIST | 3 +++ tests/auto/network/socket/qtcpsocket/BLACKLIST | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/auto/network/access/qnetworkreply/BLACKLIST b/tests/auto/network/access/qnetworkreply/BLACKLIST index d4c83bc40b5..f546f38b9e3 100644 --- a/tests/auto/network/access/qnetworkreply/BLACKLIST +++ b/tests/auto/network/access/qnetworkreply/BLACKLIST @@ -22,6 +22,9 @@ windows windows [ioPostToHttpFromSocket] windows +# QTBUG-66247 +[ioHttpRedirect] +windows [ioHttpRedirectMultipartPost] linux [ioHttpRedirectPolicy] diff --git a/tests/auto/network/socket/qtcpsocket/BLACKLIST b/tests/auto/network/socket/qtcpsocket/BLACKLIST index 96e59e5678d..d724897b74b 100644 --- a/tests/auto/network/socket/qtcpsocket/BLACKLIST +++ b/tests/auto/network/socket/qtcpsocket/BLACKLIST @@ -8,4 +8,6 @@ windows windows [timeoutConnect:ip] windows -] +# QTBUG-66247 +[taskQtBug5799ConnectionErrorEventLoop] +windows From c19d532393f54229173fd6c0adcce041fa4fd635 Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Fri, 2 Feb 2018 16:46:03 +0200 Subject: [PATCH 096/146] Fix tst_QTcpServer::maxPendingConnections flakiness Task-number: QTBUG-63152 Change-Id: I5ccd07f31d47048d81e85f69e1327f4f7c760257 Reviewed-by: Timur Pocheptsov --- tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp index 31f82539aa8..161d94d642c 100644 --- a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp +++ b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp @@ -420,13 +420,20 @@ void tst_QTcpServer::maxPendingConnections() QTcpSocket socket2; QTcpSocket socket3; + QSignalSpy spy(&server, SIGNAL(newConnection())); QVERIFY(server.listen()); socket1.connectToHost(QHostAddress::LocalHost, server.serverPort()); socket2.connectToHost(QHostAddress::LocalHost, server.serverPort()); socket3.connectToHost(QHostAddress::LocalHost, server.serverPort()); - QVERIFY(server.waitForNewConnection(5000)); + // We must have two and only two connections. First compare waits until + // two connections have been made. The second compare makes sure no + // more are accepted. Creating connections happens multithreaded so + // qWait must be used for that. + QTRY_COMPARE(spy.count(), 2); + QTest::qWait(100); + QCOMPARE(spy.count(), 2); QVERIFY(server.hasPendingConnections()); QVERIFY(server.nextPendingConnection()); From a72b6fe67685aad93062ca491e4e4cde7a87158c Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 8 Feb 2018 13:00:52 +0100 Subject: [PATCH 097/146] Blacklist tst_QtConcurrentMap::qFutureAssignmentLeak This test was blacklisted in 5.10 on opensuse, but it fails a lot on ubuntu as well. While we are discussing a real fix for this, temporarily get this out of the way. Task-number: QTBUG-63152 Change-Id: I4f1d3b261013052636ee13eda30f94b647a43a38 Reviewed-by: Sami Nurmenniemi Reviewed-by: Simon Hausmann --- tests/auto/concurrent/qtconcurrentmap/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/auto/concurrent/qtconcurrentmap/BLACKLIST diff --git a/tests/auto/concurrent/qtconcurrentmap/BLACKLIST b/tests/auto/concurrent/qtconcurrentmap/BLACKLIST new file mode 100644 index 00000000000..c92cc3e0f14 --- /dev/null +++ b/tests/auto/concurrent/qtconcurrentmap/BLACKLIST @@ -0,0 +1,3 @@ +[qFutureAssignmentLeak] +ci opensuse-42.3 +ci ubuntu-16.04 From a0da6df87be550eb3cd69e7c8de77ae781d8488b Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Feb 2018 14:09:38 +0200 Subject: [PATCH 098/146] Blacklist a flaky menubar test Task-number: QTBUG-66255 Change-Id: Ia7c493496c3fbd551e724853e4f70e3500a1bb74 Reviewed-by: Simon Hausmann --- tests/auto/widgets/widgets/qmenubar/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/auto/widgets/widgets/qmenubar/BLACKLIST b/tests/auto/widgets/widgets/qmenubar/BLACKLIST index e2194e69ca7..3bfd34782ec 100644 --- a/tests/auto/widgets/widgets/qmenubar/BLACKLIST +++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST @@ -1,3 +1,6 @@ [check_menuPosition] ubuntu-14.04 ubuntu-16.04 +#QTBUG-66255 +[activatedCount] +* From 4ba535616b8d3dfda7fbe162c6513f3008c1077a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 7 Feb 2018 23:25:06 -0800 Subject: [PATCH 099/146] QSaveFile: Check for EINTR in fsync()/fdatasync() [ChangeLog][QtCore][QSaveFile] Fixed an issue that would cause QSaveFile::commit() to fail if Unix signals were delivered at the same time. Task-number: QTBUG-66268 Change-Id: I3debfc11127e4516b505fffd151148e70662cd5e Reviewed-by: Oswald Buddenhagen Reviewed-by: David Faure --- src/corelib/io/qfsfileengine_unix.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index c040d678627..e406fb44476 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -180,10 +180,11 @@ bool QFSFileEnginePrivate::nativeFlush() bool QFSFileEnginePrivate::nativeSyncToDisk() { Q_Q(QFSFileEngine); + int ret; #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 - const int ret = fdatasync(nativeHandle()); + EINTR_LOOP(ret, fdatasync(nativeHandle())); #else - const int ret = fsync(nativeHandle()); + EINTR_LOOP(ret, fsync(nativeHandle())); #endif if (ret != 0) q->setError(QFile::WriteError, qt_error_string(errno)); From 72918d196c3617fb1cb9aee2c5f1a88e3bc30041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Tue, 30 Jan 2018 16:40:26 +0100 Subject: [PATCH 100/146] Android: Don't rely on QDir::homePath() to get the application directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the QLoggingRegistry gets called as part of the static initialization phase, it would call into Android's QStandarPaths implementation, which assumed that the HOME env. variable was already set. Since the variable isn't set before main is called, QDir::homePath() returns the root path, which would be cached and always returned. With this fix we now call Android's getFilesDir() directly, which will always return the right path. Since the font locations are also relying on an environment variable being set, we no longer cache that either. Task-number: QTBUG-65820 Change-Id: If45f3d5f0e87b808a62118ae95c31b492885646a Reviewed-by: Tor Arne Vestbø Reviewed-by: Eskil Abrahamsen Blomfeldt (cherry picked from commit eadf9e542fcc42597bfe02df065fc4cefa94cd56) --- src/corelib/io/qstandardpaths_android.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp index 2a44daf8b52..0667d170c71 100644 --- a/src/corelib/io/qstandardpaths_android.cpp +++ b/src/corelib/io/qstandardpaths_android.cpp @@ -217,7 +217,16 @@ static QString getFilesDir() if (!path.isEmpty()) return path; - return (path = QDir::homePath()); + QJNIObjectPrivate appCtx = applicationContext(); + if (!appCtx.isValid()) + return QString(); + + QJNIObjectPrivate file = appCtx.callObjectMethod("getFilesDir", + "()Ljava/io/File;"); + if (!file.isValid()) + return QString(); + + return (path = getAbsolutePath(file)); } QString QStandardPaths::writableLocation(StandardLocation type) @@ -319,7 +328,9 @@ QStringList QStandardPaths::standardLocations(StandardLocation type) if (!ba.isEmpty()) return QStringList((fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba)))); - return QStringList((fontLocation = QLatin1String("/system/fonts"))); + // Don't cache the fallback, as we might just have been called before + // QT_ANDROID_FONT_LOCATION has been set. + return QStringList(QLatin1String("/system/fonts")); } return QStringList(writableLocation(type)); From 38b6ac6544f2afb54466088a0e1e3cc771a2fd94 Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Fri, 9 Feb 2018 16:59:36 +0200 Subject: [PATCH 101/146] Skip tst_QFile::largeUncFileSupport If more than one VM tries to run the test at the same time, it times out. These sharing violations were attempted to be worked around in 1c3dc8cfb, but the workaround just leads to timeout, not success. Task-number: QTQAINFRA-1727 Task-number: QTBUG-66216 Change-Id: If8bfd60dbb6575843680971d45b1c82e5beff534 Reviewed-by: Friedemann Kleint Reviewed-by: Sami Nurmenniemi --- tests/auto/corelib/io/qfile/tst_qfile.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index 5f0eae6fc35..e92f6df419c 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -1642,6 +1642,15 @@ static bool fOpen(const QByteArray &fileName, const char *mode, FILE **file) void tst_QFile::largeUncFileSupport() { + // Currently there is a single network test server that is used by all VMs running tests in + // the CI. This test accesses a file shared with Samba on that server. Unfortunately many + // clients accessing the file at the same time is a sharing violation. This test already + // attempted to deal with the problem with retries, but that has led to the test timing out, + // not eventually succeeding. Due to the timeouts blacklisting the test wouldn't help. + // See https://bugreports.qt.io/browse/QTQAINFRA-1727 which will be resolved by the new + // test server architecture where the server is no longer shared. + QSKIP("Multiple instances of running this test at the same time fail due to QTQAINFRA-1727"); + qint64 size = Q_INT64_C(8589934592); qint64 dataOffset = Q_INT64_C(8589914592); QByteArray knownData("LargeFile content at offset 8589914592"); From a211d5379bba700766b5f626e4ab795a641a3eb3 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Sat, 10 Feb 2018 14:08:17 +0200 Subject: [PATCH 102/146] Blacklist a flaky scrollbar test on macos Task-number: QTBUG-66321 Change-Id: Ib632ffad993e178305884170fdfe17809ea1e1e6 Reviewed-by: Sami Nurmenniemi Reviewed-by: Friedemann Kleint --- tests/auto/widgets/widgets/qscrollbar/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/auto/widgets/widgets/qscrollbar/BLACKLIST diff --git a/tests/auto/widgets/widgets/qscrollbar/BLACKLIST b/tests/auto/widgets/widgets/qscrollbar/BLACKLIST new file mode 100644 index 00000000000..277ae4d2605 --- /dev/null +++ b/tests/auto/widgets/widgets/qscrollbar/BLACKLIST @@ -0,0 +1,3 @@ +#QTBUG-66321 +[QTBUG_42871] +macos From da1ca1be51213d73565984aa2f5a29a19d0c2926 Mon Sep 17 00:00:00 2001 From: Konstantin Tokarev Date: Wed, 7 Feb 2018 20:44:19 +0300 Subject: [PATCH 103/146] Remove QLibrary code path specific to HP-UX on PA-RISC The only mkspecs that enabled QT_HPUX_LD were removed in ab44ac021de. Change-Id: I9f27f0b487b69c11d19ba76801e3926b7894e6e7 Reviewed-by: Thiago Macieira Reviewed-by: Oswald Buddenhagen --- src/corelib/plugin/qlibrary_unix.cpp | 35 ++-------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 3c4fbaf348e..23b9ad6434f 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -44,25 +44,17 @@ #include #include +#include + #ifdef Q_OS_MAC # include #endif QT_BEGIN_NAMESPACE -#if !defined(QT_HPUX_LD) -QT_BEGIN_INCLUDE_NAMESPACE -#include -QT_END_INCLUDE_NAMESPACE -#endif - static QString qdlerror() { -#if !defined(QT_HPUX_LD) const char *err = dlerror(); -#else - const char *err = strerror(errno); -#endif return err ? QLatin1Char('(') + QString::fromLocal8Bit(err) + QLatin1Char(')'): QString(); } @@ -139,14 +131,6 @@ bool QLibraryPrivate::load_sys() suffixes = suffixes_sys(fullVersion); } int dlFlags = 0; -#if defined(QT_HPUX_LD) - dlFlags = DYNAMIC_PATH | BIND_NONFATAL; - if (loadHints & QLibrary::ResolveAllSymbolsHint) { - dlFlags |= BIND_IMMEDIATE; - } else { - dlFlags |= BIND_DEFERRED; - } -#else int loadHints = this->loadHints(); if (loadHints & QLibrary::ResolveAllSymbolsHint) { dlFlags |= RTLD_NOW; @@ -182,7 +166,6 @@ bool QLibraryPrivate::load_sys() dlFlags |= RTLD_MEMBER; } #endif -#endif // QT_HPUX_LD // If the filename is an absolute path then we want to try that first as it is most likely // what the callee wants. If we have been given a non-absolute path then lets try the @@ -211,11 +194,7 @@ bool QLibraryPrivate::load_sys() } else { attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix); } -#if defined(QT_HPUX_LD) - pHnd = (void*)shl_load(QFile::encodeName(attempt), dlFlags, 0); -#else pHnd = dlopen(QFile::encodeName(attempt), dlFlags); -#endif if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) { // We only want to continue if dlopen failed due to that the shared library did not exist. @@ -253,11 +232,7 @@ bool QLibraryPrivate::load_sys() bool QLibraryPrivate::unload_sys() { -#if defined(QT_HPUX_LD) - if (shl_unload((shl_t)pHnd)) { -#else if (dlclose(pHnd)) { -#endif #if defined (Q_OS_QNX) // Workaround until fixed in QNX; fixes crash in char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance if (!qstrcmp(error, "Shared objects still referenced")) // On QNX that's only "informative" @@ -289,13 +264,7 @@ Q_CORE_EXPORT QFunctionPointer qt_mac_resolve_sys(void *handle, const char *symb QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { -#if defined(QT_HPUX_LD) - QFunctionPointer address = 0; - if (shl_findsym((shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address) < 0) - address = 0; -#else QFunctionPointer address = QFunctionPointer(dlsym(pHnd, symbol)); -#endif if (!address) { errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( QString::fromLatin1(symbol), fileName, qdlerror()); From af18215a955040b7a56a2eb9281ba57dcb459f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pasi=20Pet=C3=A4j=C3=A4j=C3=A4rvi?= Date: Mon, 12 Feb 2018 13:36:45 +0200 Subject: [PATCH 104/146] Fix build failure when QtNetwork module is not build Affected plugins: tuiotouch, vnc Change-Id: Iabf72e3da0a25de0de2a861c69a29b3887ca81c3 Reviewed-by: Jesus Fernandez --- src/plugins/generic/generic.pro | 2 +- src/plugins/platforms/platforms.pro | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/generic/generic.pro b/src/plugins/generic/generic.pro index e323f32d2c0..70e433f89d6 100644 --- a/src/plugins/generic/generic.pro +++ b/src/plugins/generic/generic.pro @@ -11,7 +11,7 @@ qtConfig(tslib) { SUBDIRS += tslib } -qtConfig(udpsocket) { +qtHaveModule(network):qtConfig(udpsocket) { SUBDIRS += tuiotouch } diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 9414f01ef0f..e61887618fc 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -36,7 +36,7 @@ qtConfig(directfb) { qtConfig(linuxfb): SUBDIRS += linuxfb -qtConfig(vnc): SUBDIRS += vnc +qtHaveModule(network):qtConfig(vnc): SUBDIRS += vnc freebsd { SUBDIRS += bsdfb From c7913f3a1f56ce34e3bd4b96cbe1ffef346a5305 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Tue, 13 Feb 2018 14:54:34 +0200 Subject: [PATCH 105/146] Blacklist a flaky messagebox test Task-number: QTBUG-66371 Change-Id: I95fff726167d9fad2e2fb47891ce357d7025d254 Reviewed-by: Sami Nurmenniemi Reviewed-by: Simon Hausmann --- tests/auto/widgets/dialogs/qmessagebox/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/widgets/dialogs/qmessagebox/BLACKLIST diff --git a/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST b/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST new file mode 100644 index 00000000000..da52809aad5 --- /dev/null +++ b/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST @@ -0,0 +1,2 @@ +[defaultButton] +* From 3024fd60ae13990e2032bb7ced61c7fbadf50ad8 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Tue, 13 Feb 2018 15:38:15 +0200 Subject: [PATCH 106/146] Blacklist the positioning test on all linuxes, it fails on opensuse too Task-Id: QTQAINFRA-1332 Change-Id: I38a36c42f88671430452cdde8098961b67854ae7 Reviewed-by: Friedemann Kleint --- tests/auto/gui/kernel/qwindow/BLACKLIST | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index f86388345b4..cb186510911 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -1,6 +1,5 @@ [positioning:default] -ubuntu-14.04 -ubuntu-16.04 +linux osx-10.12 ci [positioning:fake] osx-10.12 ci From b34942710cf4e40bd9a3091032cb14baed741862 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Feb 2018 16:31:40 +0200 Subject: [PATCH 107/146] Silence a GCC 8 warning in QIODevice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtbase/src/corelib/io/qiodevice.cpp:688:60: required from here ../../../include/QtCore/../../../../qtbase/src/corelib/tools/qvector.h:727:20: error: ‘void* memmove(void*, const void*, size_t)’ writing to an object of type ‘class QRingBuffer’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Werror=class-memaccess] memmove(i, b, (d->size - offset) * sizeof(T)); ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Change-Id: I9dc9a17c281b71bf2eb3e89116600ec3ba345d74 Reviewed-by: Simon Hausmann --- src/corelib/tools/qvector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 74c37faad08..e225ce1ecba 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -724,7 +724,7 @@ typename QVector::iterator QVector::insert(iterator before, size_type n, c } else { T *b = d->begin() + offset; T *i = b + n; - memmove(i, b, (d->size - offset) * sizeof(T)); + memmove(static_cast(i), static_cast(b), (d->size - offset) * sizeof(T)); while (i != b) new (--i) T(copy); } From 77582f1f103b4f86423aa29fc7233678a399938c Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Feb 2018 17:58:38 +0200 Subject: [PATCH 108/146] Silence GCC 8 warnings in QString MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtbase/src/corelib/tools/qstring.cpp:3539:67: error: ‘void* memcpy(void*, const void*, size_t)’ copying an object of non-trivial type ‘class QChar’ from an array of ‘short unsigned int’ [-Werror=class-memaccess] memcpy(uc, d->data() + copystart, size * sizeof(QChar)); Change-Id: Ic601bed1a1f9e1b6f0ac1f9e58f1dcadb50ad724 Reviewed-by: Simon Hausmann --- src/corelib/tools/qstring.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index aff384a2577..2c96a8d33c9 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -3536,14 +3536,14 @@ QString& QString::replace(const QRegExp &rx, const QString &after) while (i < pos) { int copyend = replacements[i].pos; int size = copyend - copystart; - memcpy(uc, d->data() + copystart, size * sizeof(QChar)); + memcpy(static_cast(uc), static_cast(d->data() + copystart), size * sizeof(QChar)); uc += size; - memcpy(uc, after.d->data(), al * sizeof(QChar)); + memcpy(static_cast(uc), static_cast(after.d->data()), al * sizeof(QChar)); uc += al; copystart = copyend + replacements[i].length; i++; } - memcpy(uc, d->data() + copystart, (d->size - copystart) * sizeof(QChar)); + memcpy(static_cast(uc), static_cast(d->data() + copystart), (d->size - copystart) * sizeof(QChar)); newstring.resize(newlen); *this = newstring; caretMode = QRegExp::CaretWontMatch; @@ -5766,7 +5766,7 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const while (padlen--) * uc++ = fill; if (len) - memcpy(uc, d->data(), sizeof(QChar)*len); + memcpy(static_cast(uc), static_cast(d->data()), sizeof(QChar)*len); } else { if (truncate) result = left(width); From c97632385ec178d34f57062ca834b9908d92f327 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Feb 2018 18:06:55 +0200 Subject: [PATCH 109/146] Fix GCC 8 warning in qurlrecode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtbase/src/corelib/io/qurlrecode.cpp:514:86: error: ‘void* memcpy(void*, const void*, size_t)’ copying an object of non-trivial type ‘class QChar’ from an array of ‘const ushort’ {aka ‘const short unsigned int’} [-Werror=class-memaccess] memcpy(appendTo.begin() + origSize, begin, (end - begin) * sizeof(ushort)); Change-Id: Ide78a4144d6bc63342c3c4334cc97fe73c5167bd Reviewed-by: Simon Hausmann --- src/corelib/io/qurlrecode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qurlrecode.cpp b/src/corelib/io/qurlrecode.cpp index ce90ab49d3e..a9b23babc09 100644 --- a/src/corelib/io/qurlrecode.cpp +++ b/src/corelib/io/qurlrecode.cpp @@ -511,7 +511,7 @@ static int decode(QString &appendTo, const ushort *begin, const ushort *end) if (Q_UNLIKELY(end - input < 3 || !isHex(input[1]) || !isHex(input[2]))) { // badly-encoded data appendTo.resize(origSize + (end - begin)); - memcpy(appendTo.begin() + origSize, begin, (end - begin) * sizeof(ushort)); + memcpy(static_cast(appendTo.begin() + origSize), static_cast(begin), (end - begin) * sizeof(ushort)); return end - begin; } @@ -519,7 +519,7 @@ static int decode(QString &appendTo, const ushort *begin, const ushort *end) // detach appendTo.resize(origSize + (end - begin)); output = reinterpret_cast(appendTo.begin()) + origSize; - memcpy(output, begin, (input - begin) * sizeof(ushort)); + memcpy(static_cast(output), static_cast(begin), (input - begin) * sizeof(ushort)); output += input - begin; } From 517daa6e73fe6fd098741282bfb01cdac36c048a Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Feb 2018 18:25:05 +0200 Subject: [PATCH 110/146] Fix GCC 8 warning in qvariantanimation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtbase/src/corelib/animation/qvariantanimation.cpp:451:13: error: cast between incompatible function types from ‘QVariant (*)(const QRectF&, const QRectF&, qreal)’ {aka ‘QVariant (*)(const QRectF&, const QRectF&, double)’} to ‘QVariantAnimation::Interpolator’ {aka ‘QVariant (*)(const void*, const void*, double)’} [-Werror=cast-function-type] Change-Id: I5398316adaa0f12fbbdfdb200fd796de284821ef Reviewed-by: Simon Hausmann --- src/corelib/animation/qvariantanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index 7117092c54a..e0d7db144ac 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -448,7 +448,7 @@ void QVariantAnimation::registerInterpolator(QVariantAnimation::Interpolator fun template static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) { - return reinterpret_cast(func); + return reinterpret_cast(reinterpret_cast(func)); } QVariantAnimation::Interpolator QVariantAnimationPrivate::getInterpolator(int interpolationType) From dfffb5299bf83b87607f28f55afaf3c404910f9f Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Feb 2018 22:13:54 +0200 Subject: [PATCH 111/146] Fix build failure of qftp tests Without this fix, a fresh clean build of 5.9 will fail. Change-Id: I69e4da382b07cc6e5e280e99478cbc3d44aa3f27 Reviewed-by: Jesus Fernandez Reviewed-by: Simon Hausmann --- tests/auto/network/access/qftp/tst_qftp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/network/access/qftp/tst_qftp.cpp b/tests/auto/network/access/qftp/tst_qftp.cpp index 44ae125d375..b58e9bf558c 100644 --- a/tests/auto/network/access/qftp/tst_qftp.cpp +++ b/tests/auto/network/access/qftp/tst_qftp.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include "../../../network-settings.h" From e0a1bbc1d3cd8a1dd9e9825b6040885e0e455823 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 13 Feb 2018 16:21:57 +0100 Subject: [PATCH 112/146] Remove third-party attribution for qtemporaryfile The code got dropped already in commit 9a3ce25f983b. [ChangeLog][Third-Party Code] Removed attribution for QTemporaryFile: The original code got rewritten. Change-Id: Ib8977f88d3bd649def136e5842d013e9952ab5dd Reviewed-by: Thiago Macieira --- src/corelib/io/QTEMPORARYFILE_LICENSE.txt | 26 ----------------------- src/corelib/io/qt_attribution.json | 15 ------------- 2 files changed, 41 deletions(-) delete mode 100644 src/corelib/io/QTEMPORARYFILE_LICENSE.txt diff --git a/src/corelib/io/QTEMPORARYFILE_LICENSE.txt b/src/corelib/io/QTEMPORARYFILE_LICENSE.txt deleted file mode 100644 index f5f1a2e05ea..00000000000 --- a/src/corelib/io/QTEMPORARYFILE_LICENSE.txt +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 1987, 1993 - The Regents of the University of California. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. diff --git a/src/corelib/io/qt_attribution.json b/src/corelib/io/qt_attribution.json index 0fa4502db43..e9eb9c85e4b 100644 --- a/src/corelib/io/qt_attribution.json +++ b/src/corelib/io/qt_attribution.json @@ -1,17 +1,3 @@ -[ -{ - "Id": "qtemporaryfile", - "Name": "Parts of QTemporaryFile", - "QDocModule": "qtcore", - "QtUsage": "Used in Qt Core. Disable the qtemporaryfile feature to avoid.", - "Path": "qtemporaryfile.cpp", - - "Description": "Generates a unique file path and returns a native handle to the open file.", - "License": "BSD 3-clause \"New\" or \"Revised\" License", - "LicenseId": "BSD-3-Clause", - "LicenseFile": "QTEMPORARYFILE_LICENSE.txt", - "Copyright": "Copyright (c) 1987, 1993 The Regents of the University of California." -}, { "Id": "psl", "Name": "The Public Suffix List", @@ -39,4 +25,3 @@ supported by Qt (by the QNetworkCookieJar class).", "Copyright": "The list was originally provided by Jo Hermans . It is now maintained on github (https://github.com/publicsuffix/list)." } -] From a37dd93defd91b79fb6730d0ff0515a66a0d3972 Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Tue, 13 Feb 2018 15:10:20 +0200 Subject: [PATCH 113/146] Fix crash in tst_QStateMachine::dontProcessSlotsWhenMachineIsNotRunning The test sometimes ended up with: QThread: Destroyed while thread is still running Received a fatal error. This was because as a member variable of the local struct the QThread object was sometimes destructed before the signal connection quitting it was handled. Fix that by making sure that the thread is finished before finishing the test. Also moved connecting to the state machine's signal to be before starting the machine. Because the counting of QStateMachine::finished signal could hit 1 after the first signal is emitted and the test could pass without the code working, check that both of the signals have been emitted. Task-number: QTBUG-66372 Task-number: QTBUG-66216 Change-Id: If14141e39f37541032ddd8c6471daf40a77b0469 Reviewed-by: Frederik Gladhorn --- .../statemachine/qstatemachine/tst_qstatemachine.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp index b80c6ae8111..17763f31f95 100644 --- a/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/corelib/statemachine/qstatemachine/tst_qstatemachine.cpp @@ -6684,10 +6684,13 @@ void tst_QStateMachine::dontProcessSlotsWhenMachineIsNotRunning() machine.addState(&initialState); machine.addState(&finalState); machine.setInitialState(&initialState); - machine.start(); connect(&machine, &QStateMachine::finished, &emitter.thread, &QThread::quit); - QSignalSpy signalSpy(&machine, &QStateMachine::finished); - QTRY_COMPARE_WITH_TIMEOUT(signalSpy.count(), 1, 100); + machine.start(); + QSignalSpy emittedSpy(&emitter, &SignalEmitter::signalWithNoArg); + QSignalSpy finishedSpy(&machine, &QStateMachine::finished); + QTRY_COMPARE_WITH_TIMEOUT(emittedSpy.count(), 2, 100); + QTRY_COMPARE(finishedSpy.count(), 1); + QTRY_VERIFY(emitter.thread.isFinished()); } QTEST_MAIN(tst_QStateMachine) From 666d7745eb4f836eadc70da2bf841df5dee7a9e7 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 6 Feb 2018 13:02:47 +0100 Subject: [PATCH 114/146] Fix missing override warning Change-Id: Ib0616b203f3cf2934b7a0fd18b95111423001bab Reviewed-by: Jan Grulich Reviewed-by: Thiago Macieira --- src/plugins/platformthemes/flatpak/qflatpaktheme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platformthemes/flatpak/qflatpaktheme.h b/src/plugins/platformthemes/flatpak/qflatpaktheme.h index fcaac5b673d..87f79a23954 100644 --- a/src/plugins/platformthemes/flatpak/qflatpaktheme.h +++ b/src/plugins/platformthemes/flatpak/qflatpaktheme.h @@ -72,7 +72,7 @@ public: QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override; QIcon fileIcon(const QFileInfo &fileInfo, - QPlatformTheme::IconOptions iconOptions = 0) const; + QPlatformTheme::IconOptions iconOptions = 0) const override; QIconEngine *createIconEngine(const QString &iconName) const override; From 08f9dc1d325ac945c2e6f8f1ff6f8093b091b2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Cr=C3=A9moux?= Date: Tue, 13 Feb 2018 13:46:11 +0300 Subject: [PATCH 115/146] Fix creation of RGB texture with QOpenGLTexture/Qt3D on OpenGL ES 2.0 Modification of the function pixelFormatCompatibleWithInternalFormat to not change RGB pixel format to RGBA one, allowing the creation of valid RGB textures with Qt3D. Task-number: QTBUG-66365 Change-Id: I5c3187a3fefaedf85140f80fbb7145e1a762805b Reviewed-by: Sean Harmer Reviewed-by: Laszlo Agocs --- src/gui/opengl/qopengltexture.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index 3563f1b5d36..b825b56d45a 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -778,6 +778,8 @@ static QOpenGLTexture::PixelFormat pixelFormatCompatibleWithInternalFormat(QOpen return QOpenGLTexture::Alpha; case QOpenGLTexture::RGBFormat: + return QOpenGLTexture::RGB; + case QOpenGLTexture::RGBAFormat: return QOpenGLTexture::RGBA; From 4266c541284c9ba4e490c0b0b6ae0ef709fc01fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 13 Feb 2018 14:47:18 +0100 Subject: [PATCH 116/146] Use explicit QThreadData::hasEventDispatcher() where possible Change-Id: Ibce1a82dabb4e1381486211dbfb14eee9572e0ac Reviewed-by: Thiago Macieira --- src/corelib/kernel/qeventloop.cpp | 10 +++++----- src/corelib/kernel/qobject.cpp | 8 ++++---- src/corelib/kernel/qsocketnotifier.cpp | 4 ++-- src/corelib/thread/qthread_unix.cpp | 2 +- src/corelib/thread/qthread_win.cpp | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp index 8974ff77097..3e2326343ba 100644 --- a/src/corelib/kernel/qeventloop.cpp +++ b/src/corelib/kernel/qeventloop.cpp @@ -101,7 +101,7 @@ QEventLoop::QEventLoop(QObject *parent) Q_D(QEventLoop); if (!QCoreApplication::instance() && QCoreApplicationPrivate::threadRequiresCoreApplication()) { qWarning("QEventLoop: Cannot be used without QApplication"); - } else if (!d->threadData->eventDispatcher.load()) { + } else if (!d->threadData->hasEventDispatcher()) { QThreadPrivate::createEventDispatcher(d->threadData); } } @@ -129,7 +129,7 @@ QEventLoop::~QEventLoop() bool QEventLoop::processEvents(ProcessEventsFlags flags) { Q_D(QEventLoop); - if (!d->threadData->eventDispatcher.load()) + if (!d->threadData->hasEventDispatcher()) return false; return d->threadData->eventDispatcher.load()->processEvents(flags); } @@ -234,7 +234,7 @@ int QEventLoop::exec(ProcessEventsFlags flags) void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime) { Q_D(QEventLoop); - if (!d->threadData->eventDispatcher.load()) + if (!d->threadData->hasEventDispatcher()) return; QElapsedTimer start; @@ -263,7 +263,7 @@ void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime) void QEventLoop::exit(int returnCode) { Q_D(QEventLoop); - if (!d->threadData->eventDispatcher.load()) + if (!d->threadData->hasEventDispatcher()) return; d->returnCode.store(returnCode); @@ -292,7 +292,7 @@ bool QEventLoop::isRunning() const void QEventLoop::wakeUp() { Q_D(QEventLoop); - if (!d->threadData->eventDispatcher.load()) + if (!d->threadData->hasEventDispatcher()) return; d->threadData->eventDispatcher.load()->wakeUp(); } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 263c4019f7a..9e1c3a50cbb 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -238,7 +238,7 @@ QObjectPrivate::~QObjectPrivate() if (extraData && !extraData->runningTimers.isEmpty()) { if (Q_LIKELY(threadData->thread == QThread::currentThread())) { // unregister pending timers - if (threadData->eventDispatcher.load()) + if (threadData->hasEventDispatcher()) threadData->eventDispatcher.load()->unregisterTimers(q_ptr); // release the timer ids back to the pool @@ -1538,7 +1538,7 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData ++eventsMoved; } } - if (eventsMoved > 0 && targetData->eventDispatcher.load()) { + if (eventsMoved > 0 && targetData->hasEventDispatcher()) { targetData->canWait = false; targetData->eventDispatcher.load()->wakeUp(); } @@ -1621,7 +1621,7 @@ int QObject::startTimer(int interval, Qt::TimerType timerType) qWarning("QObject::startTimer: Timers cannot have negative intervals"); return 0; } - if (Q_UNLIKELY(!d->threadData->eventDispatcher.load())) { + if (Q_UNLIKELY(!d->threadData->hasEventDispatcher())) { qWarning("QObject::startTimer: Timers can only be used with threads started with QThread"); return 0; } @@ -1703,7 +1703,7 @@ void QObject::killTimer(int id) return; } - if (d->threadData->eventDispatcher.load()) + if (d->threadData->hasEventDispatcher()) d->threadData->eventDispatcher.load()->unregisterTimer(id); d->extraData->runningTimers.remove(at); diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp index 2268cb83bb0..6ff82689782 100644 --- a/src/corelib/kernel/qsocketnotifier.cpp +++ b/src/corelib/kernel/qsocketnotifier.cpp @@ -149,7 +149,7 @@ QSocketNotifier::QSocketNotifier(qintptr socket, Type type, QObject *parent) if (socket < 0) qWarning("QSocketNotifier: Invalid socket specified"); - else if (!d->threadData->eventDispatcher.load()) + else if (!d->threadData->hasEventDispatcher()) qWarning("QSocketNotifier: Can only be used with threads started with QThread"); else d->threadData->eventDispatcher.load()->registerSocketNotifier(this); @@ -234,7 +234,7 @@ void QSocketNotifier::setEnabled(bool enable) return; d->snenabled = enable; - if (!d->threadData->eventDispatcher.load()) // perhaps application/thread is shutting down + if (!d->threadData->hasEventDispatcher()) // perhaps application/thread is shutting down return; if (Q_UNLIKELY(thread() != QThread::currentThread())) { qWarning("QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread"); diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 1bb8e613e04..31292a05986 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -352,7 +352,7 @@ void *QThreadPrivate::start(void *arg) data->quitNow = thr->d_func()->exited; } - if (data->eventDispatcher.load()) // custom event dispatcher set? + if (data->hasEventDispatcher()) // custom event dispatcher set? data->eventDispatcher.load()->startingUp(); else createEventDispatcher(data); diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 24d3ca2d7d0..136733444c1 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -360,7 +360,7 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi data->quitNow = thr->d_func()->exited; } - if (data->eventDispatcher.load()) // custom event dispatcher set? + if (data->hasEventDispatcher()) // custom event dispatcher set? data->eventDispatcher.load()->startingUp(); else createEventDispatcher(data); From 550b8c342b32e518f79250620eaefd4714a873a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 13 Feb 2018 14:47:18 +0100 Subject: [PATCH 117/146] Don't expect QCoreApplictionPrivate::eventDispatcher to be set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QCoreApplication::setEventDispatcher sets the dispatcher on the current thread, not on QCoreApplictionPrivate, so when running init() we don't have an event dispatcher set. Change-Id: Ia008e68b70777779ab14f1f7b9eeadac9adbcf7b Reviewed-by: Thiago Macieira Reviewed-by: Tor Arne Vestbø --- src/corelib/kernel/qcoreapplication.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 4bab0b9f017..b56031e625c 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -848,8 +848,9 @@ void QCoreApplicationPrivate::init() #ifndef QT_NO_QOBJECT // use the event dispatcher created by the app programmer (if any) - if (!eventDispatcher) - eventDispatcher = threadData->eventDispatcher.load(); + Q_ASSERT(!eventDispatcher); + eventDispatcher = threadData->eventDispatcher.load(); + // otherwise we create one if (!eventDispatcher) createEventDispatcher(); From 7b72810801236cc0c25d0d515d2039db071c95bd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 12 Feb 2018 11:18:48 +0100 Subject: [PATCH 118/146] QWindowsNativeImage: Output parameters when CreateDIBSection() fails This helps to identify bugs in the backing store. Change-Id: Ib15946c8dbdc6f0a5bebe9ca9e6fea5668eb499b Reviewed-by: Oliver Wolff --- .../fontdatabases/windows/qwindowsnativeimage.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp index 67a6619b91a..b1133dca223 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp @@ -101,8 +101,10 @@ static inline HBITMAP createDIB(HDC hdc, int width, int height, uchar *bits = nullptr; HBITMAP bitmap = CreateDIBSection(hdc, reinterpret_cast(&bmi), DIB_RGB_COLORS, reinterpret_cast(&bits), 0, 0); - if (Q_UNLIKELY(!bitmap || !bits)) - qFatal("%s: CreateDIBSection failed.", __FUNCTION__); + if (Q_UNLIKELY(!bitmap || !bits)) { + qFatal("%s: CreateDIBSection failed (%dx%d, format: %d)", __FUNCTION__, + width, height, int(format)); + } *bitsIn = bits; return bitmap; From 2bfafb673c9658c8056e78253fd16ebee521ed06 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 12 Feb 2018 15:21:36 +0100 Subject: [PATCH 119/146] Fix typo in code handling Qt::AA_DontShowShortcutsInContextMenus Use Qt::AA_DontShowShortcutsInContextMenus instead of Qt::AA_DontShowIconsInMenus in the getters and helpers for formatting the action text. Streamline the code and use static method invocation. Amends c2c3452ba5b4c32d0c2d5df9193bf89986623ab5. Task-number: QTBUG-49435 Change-Id: I8827c2dc757e5899e5a26ffbf2d0b5018aa7544a Reviewed-by: David Faure --- src/widgets/kernel/qaction.cpp | 5 ++--- src/widgets/widgets/qlineedit.cpp | 5 ++--- src/widgets/widgets/qwidgettextcontrol.cpp | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp index 967b0b8ddea..8c8217bb75f 100644 --- a/src/widgets/kernel/qaction.cpp +++ b/src/widgets/kernel/qaction.cpp @@ -1332,9 +1332,8 @@ bool QAction::isShortcutVisibleInContextMenu() const { Q_D(const QAction); if (d->shortcutVisibleInContextMenu == -1) { - if (QApplication::instance()->testAttribute(Qt::AA_DontShowIconsInMenus)) - return false; - return qApp->styleHints()->showShortcutsInContextMenus(); + return !QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus) + && QGuiApplication::styleHints()->showShortcutsInContextMenus(); } return d->shortcutVisibleInContextMenu; } diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index e3b348f0efc..bdeef7cdf77 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -80,9 +80,8 @@ #include "private/qapplication_p.h" #include "private/qshortcutmap_p.h" #include "qkeysequence.h" -#define ACCEL_KEY(k) ((qApp->testAttribute(Qt::AA_DontShowIconsInMenus) \ - ? false \ - : qApp->styleHints()->showShortcutsInContextMenus()) \ +#define ACCEL_KEY(k) ((!QCoreApplication::testAttribute(Qt::AA_DontShowIconsInMenus) \ + && QGuiApplication::styleHints()->showShortcutsInContextMenus()) \ && !qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? \ QLatin1Char('\t') + QKeySequence(k).toString(QKeySequence::NativeText) : QString()) #else diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index 93158dcdbac..d3203e180bb 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -93,9 +93,8 @@ #include "private/qapplication_p.h" #include "private/qshortcutmap_p.h" #include -#define ACCEL_KEY(k) ((qApp->testAttribute(Qt::AA_DontShowIconsInMenus) \ - ? false \ - : qApp->styleHints()->showShortcutsInContextMenus()) \ +#define ACCEL_KEY(k) ((!QCoreApplication::testAttribute(Qt::AA_DontShowShortcutsInContextMenus) \ + && QGuiApplication::styleHints()->showShortcutsInContextMenus()) \ && !qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? \ QLatin1Char('\t') + QKeySequence(k).toString(QKeySequence::NativeText) : QString()) From fe5edcee602f0ab2912bbdd1a21f4309ed7dbfd6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 26 Jan 2018 08:37:40 +0100 Subject: [PATCH 120/146] Windows/QSaveFile: Fix locking issues on Dropbox drives Add a flag to QTemporaryFileEngine causing the file to be opened in non-shared mode, preventing renaming failures caused by the Dropbox driver accessing it. Task-number: QTBUG-57299 Change-Id: Id7afc3559fd15784d4166efbbd057d592b5e0ab2 Reviewed-by: Oswald Buddenhagen Reviewed-by: Oliver Wolff Reviewed-by: Thiago Macieira --- src/corelib/io/qsavefile.cpp | 2 +- src/corelib/io/qtemporaryfile.cpp | 11 +++++++---- src/corelib/io/qtemporaryfile_p.h | 7 +++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp index 56934a9a0f7..0cbc8c2234f 100644 --- a/src/corelib/io/qsavefile.cpp +++ b/src/corelib/io/qsavefile.cpp @@ -264,7 +264,7 @@ bool QSaveFile::open(OpenMode mode) } #endif - d->fileEngine = new QTemporaryFileEngine(&d->finalFileName); + d->fileEngine = new QTemporaryFileEngine(&d->finalFileName, QTemporaryFileEngine::Win32NonShared); // if the target file exists, we'll copy its permissions below, // but until then, let's ensure the temporary file is not accessible // to a third party diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 73249d7df8e..1983a22c651 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -207,7 +207,7 @@ QFileSystemEntry::NativePath QTemporaryFileName::generateNext() changed and contain the generated path name. */ static bool createFileFromTemplate(NativeFileHandle &file, QTemporaryFileName &templ, - quint32 mode, QSystemError &error) + quint32 mode, int flags, QSystemError &error) { const int maxAttempts = 16; for (int attempt = 0; attempt < maxAttempts; ++attempt) { @@ -216,16 +216,18 @@ static bool createFileFromTemplate(NativeFileHandle &file, QTemporaryFileName &t #if defined(Q_OS_WIN) Q_UNUSED(mode); + const DWORD shareMode = (flags & QTemporaryFileEngine::Win32NonShared) + ? 0u : (FILE_SHARE_READ | FILE_SHARE_WRITE); # ifndef Q_OS_WINRT file = CreateFile((const wchar_t *)path.constData(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, + shareMode, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); # else // !Q_OS_WINRT file = CreateFile2((const wchar_t *)path.constData(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, CREATE_NEW, + shareMode, CREATE_NEW, NULL); # endif // Q_OS_WINRT @@ -247,6 +249,7 @@ static bool createFileFromTemplate(NativeFileHandle &file, QTemporaryFileName &t return false; } #else // POSIX + Q_UNUSED(flags) file = QT_OPEN(path.constData(), QT_OPEN_CREAT | QT_OPEN_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, static_cast(mode)); @@ -366,7 +369,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) unnamedFile = true; d->fileEntry.clear(); } else if (st == CreateUnnamedFileStatus::NotSupported && - createFileFromTemplate(file, tfn, fileMode, error)) { + createFileFromTemplate(file, tfn, fileMode, flags, error)) { filePathIsTemplate = false; unnamedFile = false; d->fileEntry = QFileSystemEntry(tfn.path, QFileSystemEntry::FromNativePath()); diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h index fb8887af533..0fec88d3cd4 100644 --- a/src/corelib/io/qtemporaryfile_p.h +++ b/src/corelib/io/qtemporaryfile_p.h @@ -108,8 +108,10 @@ class QTemporaryFileEngine : public QFSFileEngine { Q_DECLARE_PRIVATE(QFSFileEngine) public: - QTemporaryFileEngine(const QString *templateName) - : templateName(*templateName) + enum Flags { Win32NonShared = 0x1 }; + + explicit QTemporaryFileEngine(const QString *_templateName, int _flags = 0) + : templateName(*_templateName), flags(_flags) {} void initialize(const QString &file, quint32 mode, bool nameIsTemplate = true) @@ -144,6 +146,7 @@ public: const QString &templateName; quint32 fileMode; + int flags = 0; bool filePathIsTemplate; bool filePathWasTemplate; bool unnamedFile = false; From 54d57cbd6fe9c6f668bb42f02f2674239359e6fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 13 Feb 2018 14:37:05 +0100 Subject: [PATCH 121/146] Make QThreadPrivate::createEventDispatcher do exactly what it says Leaving the logic of starting up the event dispatcher to the call site, unified both the case of a custom event dispatcher and the default event dispatcher. The data argument is left in due to the static nature of the function. Change-Id: Ia2020e39ccc67cd5a583d4e614dd978b2ec44dba Reviewed-by: Thiago Macieira --- src/corelib/kernel/qeventloop.cpp | 4 +++- src/corelib/thread/qthread_p.h | 4 ++-- src/corelib/thread/qthread_unix.cpp | 26 ++++++++++++++------------ src/corelib/thread/qthread_win.cpp | 20 +++++++++++--------- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp index 3e2326343ba..6034698349d 100644 --- a/src/corelib/kernel/qeventloop.cpp +++ b/src/corelib/kernel/qeventloop.cpp @@ -102,7 +102,9 @@ QEventLoop::QEventLoop(QObject *parent) if (!QCoreApplication::instance() && QCoreApplicationPrivate::threadRequiresCoreApplication()) { qWarning("QEventLoop: Cannot be used without QApplication"); } else if (!d->threadData->hasEventDispatcher()) { - QThreadPrivate::createEventDispatcher(d->threadData); + QAbstractEventDispatcher *eventDispatcher = QThreadPrivate::createEventDispatcher(d->threadData); + d->threadData->eventDispatcher.storeRelease(eventDispatcher); + eventDispatcher->startingUp(); } } diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index baeefd87ffc..46294a5fc8a 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -195,7 +195,7 @@ public: #endif // Q_OS_WIN QThreadData *data; - static void createEventDispatcher(QThreadData *data); + static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data); void ref() { @@ -222,7 +222,7 @@ public: static void setCurrentThread(QThread*) {} static QThread *threadForId(int) { return QThread::currentThread(); } - static void createEventDispatcher(QThreadData *data); + static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data); void ref() {} void deref() {} diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 31292a05986..2c815b870a2 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -285,27 +285,26 @@ typedef void*(*QtThreadCallback)(void*); #endif // QT_NO_THREAD -void QThreadPrivate::createEventDispatcher(QThreadData *data) +QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *data) { + Q_UNUSED(data); #if defined(Q_OS_DARWIN) bool ok = false; int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok); if (ok && value > 0) - data->eventDispatcher.storeRelease(new QEventDispatcherCoreFoundation); + return new QEventDispatcherCoreFoundation; else - data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); + return new QEventDispatcherUNIX; #elif !defined(QT_NO_GLIB) if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB") && QEventDispatcherGlib::versionSupported()) - data->eventDispatcher.storeRelease(new QEventDispatcherGlib); + return new QEventDispatcherGlib; else - data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); + return new QEventDispatcherUNIX; #else - data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); + return new QEventDispatcherUNIX; #endif - - data->eventDispatcher.load()->startingUp(); } #ifndef QT_NO_THREAD @@ -352,10 +351,13 @@ void *QThreadPrivate::start(void *arg) data->quitNow = thr->d_func()->exited; } - if (data->hasEventDispatcher()) // custom event dispatcher set? - data->eventDispatcher.load()->startingUp(); - else - createEventDispatcher(data); + QAbstractEventDispatcher *eventDispatcher = data->eventDispatcher.load(); + if (!eventDispatcher) { + eventDispatcher = createEventDispatcher(data); + data->eventDispatcher.storeRelease(eventDispatcher); + } + + eventDispatcher->startingUp(); #if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX)) { diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 136733444c1..4459ae87af7 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -331,15 +331,14 @@ void qt_set_thread_name(HANDLE threadId, LPCSTR threadName) #endif // QT_NO_THREAD -void QThreadPrivate::createEventDispatcher(QThreadData *data) +QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *data) { + Q_UNUSED(data); #ifndef Q_OS_WINRT - QEventDispatcherWin32 *theEventDispatcher = new QEventDispatcherWin32; + return new QEventDispatcherWin32; #else - QEventDispatcherWinRT *theEventDispatcher = new QEventDispatcherWinRT; + return new QEventDispatcherWinRT; #endif - data->eventDispatcher.storeRelease(theEventDispatcher); - theEventDispatcher->startingUp(); } #ifndef QT_NO_THREAD @@ -360,10 +359,13 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi data->quitNow = thr->d_func()->exited; } - if (data->hasEventDispatcher()) // custom event dispatcher set? - data->eventDispatcher.load()->startingUp(); - else - createEventDispatcher(data); + QAbstractEventDispatcher *eventDispatcher = data->eventDispatcher.load(); + if (!eventDispatcher) { + eventDispatcher = createEventDispatcher(data); + data->eventDispatcher.storeRelease(eventDispatcher); + } + + eventDispatcher->startingUp(); #if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) && !defined(Q_OS_WINRT) // sets the name of the current thread. From 716e4a0414128f275a8c17e072a055de22cd8dba Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Wed, 14 Feb 2018 10:23:58 +0200 Subject: [PATCH 122/146] Blacklist tst_QWidget::moveInResizeEvent on Ubuntu Previous version of Ubuntu used to be blacklisted and the test is still flaky on Ubuntu 16.04. Task-number: QTBUG-66390 Task-number: QTBUG-66216 Change-Id: Iec404879f61164b995f0df7348f4f4baf608ca90 Reviewed-by: Friedemann Kleint --- tests/auto/widgets/kernel/qwidget/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/widgets/kernel/qwidget/BLACKLIST b/tests/auto/widgets/kernel/qwidget/BLACKLIST index c822539966a..2ca30f98c3b 100644 --- a/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -59,6 +59,8 @@ osx osx [setToolTip] osx +[moveInResizeEvent] +ubuntu-16.04 [moveChild:right] osx [activateWindow] From 2aeb2bcef48d7bca2186c262dde433737956a539 Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Wed, 14 Feb 2018 12:16:30 +0200 Subject: [PATCH 123/146] Blacklist tst_QGraphicsView::update2 on openSUSE 42.3 Has been failing on it, but not on any other platform. Task-number: QTBUG-66396 Task-number: QTBUG-66216 Change-Id: I0b208c675a23fb4bc1808dd3aa4dfef9bddf136b Reviewed-by: Gatis Paeglis --- tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST index 40d106e3bae..bc83dad714f 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST +++ b/tests/auto/widgets/graphicsview/qgraphicsview/BLACKLIST @@ -14,3 +14,5 @@ xcb xcb [resizeAnchor] xcb +[update2] +opensuse-42.3 From e843e3bb00d26c841bd7132c00779c085368eab3 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 14 Feb 2018 12:38:19 +0100 Subject: [PATCH 124/146] Fix compiling qfloat16_f16c.c with C89 compiler Needed by gcc 4.8 Change-Id: I2daa5728761599255cf3912d37e7b9dd60ccb60c Reviewed-by: Eirik Aavitsland --- src/corelib/global/qfloat16_f16c.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/corelib/global/qfloat16_f16c.c b/src/corelib/global/qfloat16_f16c.c index 31dff0b154f..a7eadc71b7b 100644 --- a/src/corelib/global/qfloat16_f16c.c +++ b/src/corelib/global/qfloat16_f16c.c @@ -57,6 +57,7 @@ QT_FUNCTION_TARGET(F16C) void qFloatToFloat16_fast(quint16 *out, const float *in, qsizetype len) Q_DECL_NOTHROW { qsizetype i = 0; + int epilog_i; for (; i < len - 7; i += 8) _mm_storeu_si128((__m128i *)(out + i), _mm256_cvtps_ph(_mm256_loadu_ps(in + i), 0)); if (i < len - 3) { @@ -64,7 +65,7 @@ void qFloatToFloat16_fast(quint16 *out, const float *in, qsizetype len) Q_DECL_N i += 4; } // Inlining "qfloat16::qfloat16(float f)": - SIMD_EPILOGUE(i, len, 3) + for (epilog_i = 0; i < len && epilog_i < 3; ++i, ++epilog_i) out[i] = _mm_extract_epi16(_mm_cvtps_ph(_mm_set_ss(in[i]), 0), 0); } @@ -72,6 +73,7 @@ QT_FUNCTION_TARGET(F16C) void qFloatFromFloat16_fast(float *out, const quint16 *in, qsizetype len) Q_DECL_NOTHROW { qsizetype i = 0; + int epilog_i; for (; i < len - 7; i += 8) _mm256_storeu_ps(out + i, _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(in + i)))); if (i < len - 3) { @@ -79,7 +81,7 @@ void qFloatFromFloat16_fast(float *out, const quint16 *in, qsizetype len) Q_DECL i += 4; } // Inlining "qfloat16::operator float()": - SIMD_EPILOGUE(i, len, 3) + for (epilog_i = 0; i < len && epilog_i < 3; ++i, ++epilog_i) out[i] = _mm_cvtss_f32(_mm_cvtph_ps(_mm_cvtsi32_si128(in[i]))); } From c4e41fa534620a29b3df1349a54993a42faa543e Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 5 Feb 2018 20:44:46 -0800 Subject: [PATCH 125/146] QStyleHelper: Remove unused function setWidgetSizePolicy() This used to be public back when QMacStyle had public API. Long replaced by the WA_Mac*Size attributes. Change-Id: Ifd948e648ec90ff29b6b3652bc9d5cb1dc9c6a09 Reviewed-by: Jake Petroules --- src/widgets/styles/qstylehelper.cpp | 8 -------- src/widgets/styles/qstylehelper_p.h | 1 - 2 files changed, 9 deletions(-) diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp index 373699a7aa1..8679d96eda9 100644 --- a/src/widgets/styles/qstylehelper.cpp +++ b/src/widgets/styles/qstylehelper.cpp @@ -411,14 +411,6 @@ QWindow *styleObjectWindow(QObject *so) return 0; } -void setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy) -{ - QWidget *wadget = const_cast(widget); - wadget->setAttribute(Qt::WA_MacNormalSize, policy == SizeLarge); - wadget->setAttribute(Qt::WA_MacSmallSize, policy == SizeSmall); - wadget->setAttribute(Qt::WA_MacMiniSize, policy == SizeMini); -} - WidgetSizePolicy widgetSizePolicy(const QWidget *widget, const QStyleOption *opt) { while (widget) { diff --git a/src/widgets/styles/qstylehelper_p.h b/src/widgets/styles/qstylehelper_p.h index bd263cea7b0..260860bf4d6 100644 --- a/src/widgets/styles/qstylehelper_p.h +++ b/src/widgets/styles/qstylehelper_p.h @@ -94,7 +94,6 @@ namespace QStyleHelper enum WidgetSizePolicy { SizeLarge = 0, SizeSmall = 1, SizeMini = 2, SizeDefault = -1 }; - void setWidgetSizePolicy(const QWidget *w, WidgetSizePolicy policy); Q_WIDGETS_EXPORT WidgetSizePolicy widgetSizePolicy(const QWidget *w, const QStyleOption *opt = 0); } From 8920bf32eebe03cfc8a1a5e97f5b34c09c79a11b Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 14 Feb 2018 20:28:36 +0100 Subject: [PATCH 126/146] Reapply 0d9208cecbbd9ed08e4ffb6540729668e3bd7754 on 5.11 This change amends 305dd1b61f657474d751cc3b24f58249ec21b61b, which lost 0d9208ce and brought src/plugins/styles/mac/qmacstyle_mac.mm back. In 4f3249f32dbe5c20aabbfd9b4f9c558aaf449e48, it was moved to src/plugins/styles/mac in 5.10. Task-number: QTBUG-65773 Change-Id: I721268caf12067ed798f5846234cd2fdf3e493dc Reviewed-by: Gabriel de Dietrich Reviewed-by: Jake Petroules --- src/plugins/styles/mac/qmacstyle_mac.mm | 8 +- src/widgets/styles/qmacstyle_mac.mm | 7160 ----------------------- 2 files changed, 3 insertions(+), 7165 deletions(-) delete mode 100644 src/widgets/styles/qmacstyle_mac.mm diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index df2b637630c..9e8af78a8e4 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3348,13 +3348,12 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai } break; case PE_IndicatorMenuCheckMark: { - if (!(opt->state & State_On)) - break; QColor pc; - if (opt->state & State_Selected) + if (opt->state & State_On) pc = opt->palette.highlightedText().color(); else pc = opt->palette.text().color(); + QCFType checkmarkColor = CGColorCreateGenericRGB(static_cast(pc.redF()), static_cast(pc.greenF()), static_cast(pc.blueF()), @@ -4273,8 +4272,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter const int xp = mi->rect.x() + macItemFrame; checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh); - checkmarkOpt.state |= State_On; // Always on. Never rendered when off. - checkmarkOpt.state.setFlag(State_Selected, active); + checkmarkOpt.state.setFlag(State_On, active); checkmarkOpt.state.setFlag(State_Enabled, enabled); if (widgetSize == QStyleHelper::SizeMini) checkmarkOpt.state |= State_Mini; diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm deleted file mode 100644 index e6436f82a64..00000000000 --- a/src/widgets/styles/qmacstyle_mac.mm +++ /dev/null @@ -1,7160 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWidgets module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/* - Note: The qdoc comments for QMacStyle are contained in - .../doc/src/qstyles.qdoc. -*/ - -#include - -#include "qmacstyle_mac_p.h" -#include "qmacstyle_mac_p_p.h" - -#define QMAC_QAQUASTYLE_SIZE_CONSTRAIN -//#define DEBUG_SIZE_CONSTRAINT - -#include -#if QT_CONFIG(tabbar) -#include -#endif -#include -#include -#include -#if QT_CONFIG(combobox) -#include -#include -#endif -#if QT_CONFIG(dialogbuttonbox) -#include -#endif -#if QT_CONFIG(dockwidget) -#include -#endif -#include -#include -#include -#include -#include -#include -#if QT_CONFIG(lineedit) -#include -#endif -#if QT_CONFIG(mainwindow) -#include -#endif -#if QT_CONFIG(mdiarea) -#include -#endif -#if QT_CONFIG(menubar) -#include -#endif -#include -#include -#include -#include -#if QT_CONFIG(progressbar) -#include -#endif -#if QT_CONFIG(pushbutton) -#include -#endif -#include -#if QT_CONFIG(rubberband) -#include -#endif -#if QT_CONFIG(scrollbar) -#include -#endif -#if QT_CONFIG(sizegrip) -#include -#endif -#include -#include -#if QT_CONFIG(toolbutton) -#include -#endif -#if QT_CONFIG(treeview) -#include -#endif -#if QT_CONFIG(tableview) -#include -#endif -#include -#if QT_CONFIG(wizard) -#include -#endif -#include -#include -#if QT_CONFIG(datetimeedit) -#include -#endif -#include -#include -#if QT_CONFIG(graphicsview) -#include -#endif -#include -#include -#include -#include -#include -#include - -QT_USE_NAMESPACE - -static QWindow *qt_getWindow(const QWidget *widget) -{ - return widget ? widget->window()->windowHandle() : 0; -} - -@interface QT_MANGLE_NAMESPACE(NotificationReceiver) : NSObject { -QMacStylePrivate *mPrivate; -} -- (id)initWithPrivate:(QMacStylePrivate *)priv; -- (void)scrollBarStyleDidChange:(NSNotification *)notification; -@end - -QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver); - -@implementation NotificationReceiver -- (id)initWithPrivate:(QMacStylePrivate *)priv -{ - self = [super init]; - mPrivate = priv; - return self; -} - -- (void)scrollBarStyleDidChange:(NSNotification *)notification -{ - Q_UNUSED(notification); - - // purge destroyed scroll bars: - QMacStylePrivate::scrollBars.removeAll(QPointer()); - - QEvent event(QEvent::StyleChange); - for (const auto &o : QMacStylePrivate::scrollBars) - QCoreApplication::sendEvent(o, &event); -} -@end - -QT_BEGIN_NAMESPACE - -// The following constants are used for adjusting the size -// of push buttons so that they are drawn inside their bounds. -const int QMacStylePrivate::PushButtonLeftOffset = 6; -const int QMacStylePrivate::PushButtonTopOffset = 4; -const int QMacStylePrivate::PushButtonRightOffset = 12; -const int QMacStylePrivate::PushButtonBottomOffset = 12; -const int QMacStylePrivate::MiniButtonH = 26; -const int QMacStylePrivate::SmallButtonH = 30; -const int QMacStylePrivate::BevelButtonW = 50; -const int QMacStylePrivate::BevelButtonH = 22; -const int QMacStylePrivate::PushButtonContentPadding = 6; - -QVector > QMacStylePrivate::scrollBars; - -// Title bar gradient colors for Lion were determined by inspecting PSDs exported -// using CoreUI's CoreThemeDocument; there is no public API to retrieve them - -static QLinearGradient titlebarGradientActive() -{ - static QLinearGradient gradient; - if (gradient == QLinearGradient()) { - gradient.setColorAt(0, QColor(235, 235, 235)); - gradient.setColorAt(0.5, QColor(210, 210, 210)); - gradient.setColorAt(0.75, QColor(195, 195, 195)); - gradient.setColorAt(1, QColor(180, 180, 180)); - } - return gradient; -} - -static QLinearGradient titlebarGradientInactive() -{ - static QLinearGradient gradient; - if (gradient == QLinearGradient()) { - gradient.setColorAt(0, QColor(250, 250, 250)); - gradient.setColorAt(1, QColor(225, 225, 225)); - } - return gradient; -} - -static const QColor titlebarSeparatorLineActive(111, 111, 111); -static const QColor titlebarSeparatorLineInactive(131, 131, 131); - -// Gradient colors used for the dock widget title bar and -// non-unifed tool bar bacground. -static const QColor mainWindowGradientBegin(240, 240, 240); -static const QColor mainWindowGradientEnd(200, 200, 200); - -static const int DisclosureOffset = 4; - -// Tab bar colors -// active: window is active -// selected: tab is selected -// hovered: tab is hovered -static const QColor tabBarTabBackgroundActive(190, 190, 190); -static const QColor tabBarTabBackgroundActiveHovered(178, 178, 178); -static const QColor tabBarTabBackgroundActiveSelected(211, 211, 211); -static const QColor tabBarTabBackground(227, 227, 227); -static const QColor tabBarTabBackgroundSelected(246, 246, 246); -static const QColor tabBarTabLineActive(160, 160, 160); -static const QColor tabBarTabLineActiveHovered(150, 150, 150); -static const QColor tabBarTabLine(210, 210, 210); -static const QColor tabBarTabLineSelected(189, 189, 189); -static const QColor tabBarCloseButtonBackgroundHovered(162, 162, 162); -static const QColor tabBarCloseButtonBackgroundPressed(153, 153, 153); -static const QColor tabBarCloseButtonBackgroundSelectedHovered(192, 192, 192); -static const QColor tabBarCloseButtonBackgroundSelectedPressed(181, 181, 181); -static const QColor tabBarCloseButtonCross(100, 100, 100); -static const QColor tabBarCloseButtonCrossSelected(115, 115, 115); - -static const int closeButtonSize = 14; -static const qreal closeButtonCornerRadius = 2.0; - -// Resolve these at run-time, since the functions was moved in Leopard. -typedef HIRect * (*PtrHIShapeGetBounds)(HIShapeRef, HIRect *); -static PtrHIShapeGetBounds ptrHIShapeGetBounds = 0; - -#if QT_CONFIG(tabbar) -static bool isVerticalTabs(const QTabBar::Shape shape) { - return (shape == QTabBar::RoundedEast - || shape == QTabBar::TriangularEast - || shape == QTabBar::RoundedWest - || shape == QTabBar::TriangularWest); -} -#endif - -static bool isInMacUnifiedToolbarArea(QWindow *window, int windowY) -{ - QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); - QPlatformNativeInterface::NativeResourceForIntegrationFunction function = - nativeInterface->nativeResourceFunctionForIntegration("testContentBorderPosition"); - if (!function) - return false; // Not Cocoa platform plugin. - - typedef bool (*TestContentBorderPositionFunction)(QWindow *, int); - return (reinterpret_cast(function))(window, windowY); -} - - -static void drawTabCloseButton(QPainter *p, bool hover, bool selected, bool pressed, bool documentMode) -{ - p->setRenderHints(QPainter::Antialiasing); - QRect rect(0, 0, closeButtonSize, closeButtonSize); - const int width = rect.width(); - const int height = rect.height(); - - if (hover) { - // draw background circle - QColor background; - if (selected) { - if (documentMode) - background = pressed ? tabBarCloseButtonBackgroundSelectedPressed : tabBarCloseButtonBackgroundSelectedHovered; - else - background = QColor(255, 255, 255, pressed ? 150 : 100); // Translucent white - } else { - background = pressed ? tabBarCloseButtonBackgroundPressed : tabBarCloseButtonBackgroundHovered; - if (!documentMode) - background = background.lighter(pressed ? 135 : 140); // Lighter tab background, lighter color - } - - p->setPen(Qt::transparent); - p->setBrush(background); - p->drawRoundedRect(rect, closeButtonCornerRadius, closeButtonCornerRadius); - } - - // draw cross - const int margin = 3; - QPen crossPen; - crossPen.setColor(selected ? (documentMode ? tabBarCloseButtonCrossSelected : Qt::white) : tabBarCloseButtonCross); - crossPen.setWidthF(1.1); - crossPen.setCapStyle(Qt::FlatCap); - p->setPen(crossPen); - p->drawLine(margin, margin, width - margin, height - margin); - p->drawLine(margin, height - margin, width - margin, margin); -} - -#if QT_CONFIG(tabbar) -QRect rotateTabPainter(QPainter *p, QTabBar::Shape shape, QRect tabRect) -{ - if (isVerticalTabs(shape)) { - int newX, newY, newRot; - if (shape == QTabBar::RoundedEast - || shape == QTabBar::TriangularEast) { - newX = tabRect.width(); - newY = tabRect.y(); - newRot = 90; - } else { - newX = 0; - newY = tabRect.y() + tabRect.height(); - newRot = -90; - } - tabRect.setRect(0, 0, tabRect.height(), tabRect.width()); - QMatrix m; - m.translate(newX, newY); - m.rotate(newRot); - p->setMatrix(m, true); - } - return tabRect; -} - -void drawTabShape(QPainter *p, const QStyleOptionTab *tabOpt, bool isUnified, int tabOverlap) -{ - QRect rect = tabOpt->rect; - - switch (tabOpt->shape) { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - rect.adjust(-tabOverlap, 0, 0, 0); - break; - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - rect.adjust(0, -tabOverlap, 0, 0); - break; - default: - break; - } - - p->translate(rect.x(), rect.y()); - rect.moveLeft(0); - rect.moveTop(0); - const QRect tabRect = rotateTabPainter(p, tabOpt->shape, rect); - - const int width = tabRect.width(); - const int height = tabRect.height(); - const bool active = (tabOpt->state & QStyle::State_Active); - const bool selected = (tabOpt->state & QStyle::State_Selected); - - const QRect bodyRect(1, 1, width - 2, height - 2); - const QRect topLineRect(1, 0, width - 2, 1); - const QRect bottomLineRect(1, height - 1, width - 2, 1); - if (selected) { - // fill body - if (tabOpt->documentMode && isUnified) { - p->save(); - p->setCompositionMode(QPainter::CompositionMode_Source); - p->fillRect(tabRect, QColor(Qt::transparent)); - p->restore(); - } else if (active) { - p->fillRect(bodyRect, tabBarTabBackgroundActiveSelected); - // top line - p->fillRect(topLineRect, tabBarTabLineSelected); - } else { - p->fillRect(bodyRect, tabBarTabBackgroundSelected); - } - } else { - // when the mouse is over non selected tabs they get a new color - const bool hover = (tabOpt->state & QStyle::State_MouseOver); - if (hover) { - // fill body - p->fillRect(bodyRect, tabBarTabBackgroundActiveHovered); - // bottom line - p->fillRect(bottomLineRect, tabBarTabLineActiveHovered); - } - } - - // separator lines between tabs - const QRect leftLineRect(0, 1, 1, height - 2); - const QRect rightLineRect(width - 1, 1, 1, height - 2); - const QColor separatorLineColor = active ? tabBarTabLineActive : tabBarTabLine; - p->fillRect(leftLineRect, separatorLineColor); - p->fillRect(rightLineRect, separatorLineColor); -} - -void drawTabBase(QPainter *p, const QStyleOptionTabBarBase *tbb, const QWidget *w) -{ - QRect r = tbb->rect; - if (isVerticalTabs(tbb->shape)) { - r.setWidth(w->width()); - } else { - r.setHeight(w->height()); - } - const QRect tabRect = rotateTabPainter(p, tbb->shape, r); - const int width = tabRect.width(); - const int height = tabRect.height(); - const bool active = (tbb->state & QStyle::State_Active); - - // fill body - const QRect bodyRect(0, 1, width, height - 1); - const QColor bodyColor = active ? tabBarTabBackgroundActive : tabBarTabBackground; - p->fillRect(bodyRect, bodyColor); - - // top line - const QRect topLineRect(0, 0, width, 1); - const QColor topLineColor = active ? tabBarTabLineActive : tabBarTabLine; - p->fillRect(topLineRect, topLineColor); - - // bottom line - const QRect bottomLineRect(0, height - 1, width, 1); - const QColor bottomLineColor = active ? tabBarTabLineActive : tabBarTabLine; - p->fillRect(bottomLineRect, bottomLineColor); -} -#endif - -static int getControlSize(const QStyleOption *option, const QWidget *widget) -{ - switch (QMacStyle::widgetSizePolicy(widget, option)) { - case QMacStyle::SizeSmall: - return QAquaSizeSmall; - case QMacStyle::SizeMini: - return QAquaSizeMini; - default: - break; - } - return QAquaSizeLarge; -} - - -#if QT_CONFIG(treeview) -static inline bool isTreeView(const QWidget *widget) -{ - return (widget && widget->parentWidget() && - (qobject_cast(widget->parentWidget()) - )); -} -#endif - -#if QT_CONFIG(tabbar) -static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape) -{ - ThemeTabDirection ttd; - switch (shape) { - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - ttd = kThemeTabSouth; - break; - default: // Added to remove the warning, since all values are taken care of, really! - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - ttd = kThemeTabNorth; - break; - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - ttd = kThemeTabWest; - break; - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - ttd = kThemeTabEast; - break; - } - return ttd; -} -#endif - -static QString qt_mac_removeMnemonics(const QString &original) -{ - QString returnText(original.size(), 0); - int finalDest = 0; - int currPos = 0; - int l = original.length(); - while (l) { - if (original.at(currPos) == QLatin1Char('&') - && (l == 1 || original.at(currPos + 1) != QLatin1Char('&'))) { - ++currPos; - --l; - if (l == 0) - break; - } else if (original.at(currPos) == QLatin1Char('(') && l >= 4 && - original.at(currPos + 1) == QLatin1Char('&') && - original.at(currPos + 2) != QLatin1Char('&') && - original.at(currPos + 3) == QLatin1Char(')')) { - /* remove mnemonics its format is "\s*(&X)" */ - int n = 0; - while (finalDest > n && returnText.at(finalDest - n - 1).isSpace()) - ++n; - finalDest -= n; - currPos += 4; - l -= 4; - continue; - } - returnText[finalDest] = original.at(currPos); - ++currPos; - ++finalDest; - --l; - } - returnText.truncate(finalDest); - return returnText; -} - -OSStatus qt_mac_shape2QRegionHelper(int inMessage, HIShapeRef, const CGRect *inRect, void *inRefcon) -{ - QRegion *region = static_cast(inRefcon); - if (!region) - return paramErr; - - switch (inMessage) { - case kHIShapeEnumerateRect: - *region += QRect(inRect->origin.x, inRect->origin.y, - inRect->size.width, inRect->size.height); - break; - case kHIShapeEnumerateInit: - // Assume the region is already setup correctly - case kHIShapeEnumerateTerminate: - default: - break; - } - return noErr; -} - -/*! - \internal - Create's a mutable shape, it's the caller's responsibility to release. - WARNING: this function clamps the coordinates to SHRT_MIN/MAX on 10.4 and below. -*/ -HIMutableShapeRef qt_mac_toHIMutableShape(const QRegion ®ion) -{ - HIMutableShapeRef shape = HIShapeCreateMutable(); - if (region.rectCount() < 2 ) { - QRect qtRect = region.boundingRect(); - CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height()); - HIShapeUnionWithRect(shape, &cgRect); - } else { - for (const QRect &qtRect : region) { - CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height()); - HIShapeUnionWithRect(shape, &cgRect); - } - } - return shape; -} - -QRegion qt_mac_fromHIShapeRef(HIShapeRef shape) -{ - QRegion returnRegion; - //returnRegion.detach(); - HIShapeEnumerate(shape, kHIShapeParseFromTopLeft, qt_mac_shape2QRegionHelper, &returnRegion); - return returnRegion; -} - -bool qt_macWindowIsTextured(const QWidget *window) -{ - if (QWindow *w = window->windowHandle()) - if (w->handle()) - if (NSWindow *nswindow = static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("NSWindow"), w))) - return ([nswindow styleMask] & NSTexturedBackgroundWindowMask) ? true : false; - return false; -} - -static bool qt_macWindowMainWindow(const QWidget *window) -{ - if (QWindow *w = window->windowHandle()) { - if (w->handle()) { - if (NSWindow *nswindow = static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("nswindow"), w))) { - return [nswindow isMainWindow]; - } - } - } - return false; -} - -/***************************************************************************** - QMacCGStyle globals - *****************************************************************************/ -const int qt_mac_hitheme_version = 0; //the HITheme version we speak -const int macItemFrame = 2; // menu item frame width -const int macItemHMargin = 3; // menu item hor text margin -const int macRightBorder = 12; // right border on mac -const ThemeWindowType QtWinType = kThemeDocumentWindow; // Window type we use for QTitleBar. -QPixmap *qt_mac_backgroundPattern = 0; // stores the standard widget background. - -/***************************************************************************** - QMacCGStyle utility functions - *****************************************************************************/ -static inline int qt_mac_hitheme_tab_version() -{ - return 1; -} - -static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect()) -{ - return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(), - convertRect.width() - rect.width(), convertRect.height() - rect.height()); -} - -static inline const QRect qt_qrectForHIRect(const HIRect &hirect) -{ - return QRect(QPoint(int(hirect.origin.x), int(hirect.origin.y)), - QSize(int(hirect.size.width), int(hirect.size.height))); -} - -inline bool qt_mac_is_metal(const QWidget *w) -{ - for (; w; w = w->parentWidget()) { - if (w->testAttribute(Qt::WA_MacBrushedMetal)) - return true; - if (w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) { // If not created will fall through to the opaque check and be fine anyway. - return qt_macWindowIsTextured(w); - } -#ifndef QT_NO_ACCESSIBILITY - if (w->d_func()->isOpaque) - break; -#endif - } - return false; -} - -static int qt_mac_aqua_get_metric(ThemeMetric met) -{ - SInt32 ret; - GetThemeMetric(met, &ret); - return ret; -} - -static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg, QSize szHint, - QAquaWidgetSize sz) -{ - QSize ret(-1, -1); - if (sz != QAquaSizeSmall && sz != QAquaSizeLarge && sz != QAquaSizeMini) { - qDebug("Not sure how to return this..."); - return ret; - } - if ((widg && widg->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) { - // If you're using a custom font and it's bigger than the default font, - // then no constraints for you. If you are smaller, we can try to help you out - QFont font = qt_app_fonts_hash()->value(widg->metaObject()->className(), QFont()); - if (widg->font().pointSize() > font.pointSize()) - return ret; - } - - if (ct == QStyle::CT_CustomBase && widg) { -#if QT_CONFIG(pushbutton) - if (qobject_cast(widg)) - ct = QStyle::CT_PushButton; -#endif - else if (qobject_cast(widg)) - ct = QStyle::CT_RadioButton; -#if QT_CONFIG(checkbox) - else if (qobject_cast(widg)) - ct = QStyle::CT_CheckBox; -#endif -#if QT_CONFIG(combobox) - else if (qobject_cast(widg)) - ct = QStyle::CT_ComboBox; -#endif -#if QT_CONFIG(toolbutton) - else if (qobject_cast(widg)) - ct = QStyle::CT_ToolButton; -#endif - else if (qobject_cast(widg)) - ct = QStyle::CT_Slider; -#if QT_CONFIG(progressbar) - else if (qobject_cast(widg)) - ct = QStyle::CT_ProgressBar; -#endif -#if QT_CONFIG(lineedit) - else if (qobject_cast(widg)) - ct = QStyle::CT_LineEdit; -#endif - else if (qobject_cast(widg)) - ct = QStyle::CT_HeaderSection; -#if QT_CONFIG(menubar) - else if (qobject_cast(widg)) - ct = QStyle::CT_MenuBar; -#endif -#if QT_CONFIG(sizegrip) - else if (qobject_cast(widg)) - ct = QStyle::CT_SizeGrip; -#endif - else - return ret; - } - - switch (ct) { -#if QT_CONFIG(pushbutton) - case QStyle::CT_PushButton: { - const QPushButton *psh = qobject_cast(widg); - // If this comparison is false, then the widget was not a push button. - // This is bad and there's very little we can do since we were requested to find a - // sensible size for a widget that pretends to be a QPushButton but is not. - if(psh) { - QString buttonText = qt_mac_removeMnemonics(psh->text()); - if (buttonText.contains(QLatin1Char('\n'))) - ret = QSize(-1, -1); - else if (sz == QAquaSizeLarge) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight)); - else if (sz == QAquaSizeSmall) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight)); - else if (sz == QAquaSizeMini) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight)); - - if (!psh->icon().isNull()){ - // If the button got an icon, and the icon is larger than the - // button, we can't decide on a default size - ret.setWidth(-1); - if (ret.height() < psh->iconSize().height()) - ret.setHeight(-1); - } - else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){ - // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels. - // However, this doesn't work for German, therefore only do it for English, - // I suppose it would be better to do some sort of lookups for languages - // that like to have really long words. - ret.setWidth(77 - 8); - } - } else { - // The only sensible thing to do is to return whatever the style suggests... - if (sz == QAquaSizeLarge) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight)); - else if (sz == QAquaSizeSmall) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight)); - else if (sz == QAquaSizeMini) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight)); - else - // Since there's no default size we return the large size... - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight)); - } -#endif -#if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam - } else if (ct == QStyle::CT_RadioButton) { - QRadioButton *rdo = static_cast(widg); - // Exception for case where multiline radio button text requires no size constrainment - if (rdo->text().find('\n') != -1) - return ret; - if (sz == QAquaSizeLarge) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricRadioButtonHeight)); - else if (sz == QAquaSizeSmall) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallRadioButtonHeight)); - else if (sz == QAquaSizeMini) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniRadioButtonHeight)); - } else if (ct == QStyle::CT_CheckBox) { - if (sz == QAquaSizeLarge) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricCheckBoxHeight)); - else if (sz == QAquaSizeSmall) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallCheckBoxHeight)); - else if (sz == QAquaSizeMini) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniCheckBoxHeight)); -#endif - break; - } - case QStyle::CT_SizeGrip: - if (sz == QAquaSizeLarge || sz == QAquaSizeSmall) { - HIRect r; - HIPoint p = { 0, 0 }; - HIThemeGrowBoxDrawInfo gbi; - gbi.version = 0; - gbi.state = kThemeStateActive; - gbi.kind = kHIThemeGrowBoxKindNormal; - gbi.direction = QApplication::isRightToLeft() ? kThemeGrowLeft | kThemeGrowDown - : kThemeGrowRight | kThemeGrowDown; - gbi.size = sz == QAquaSizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal; - if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr) { - int width = 0; -#if QT_CONFIG(mdiarea) - if (widg && qobject_cast(widg->parentWidget())) - width = r.size.width; -#endif - ret = QSize(width, r.size.height); - } - } - break; - case QStyle::CT_ComboBox: - switch (sz) { - case QAquaSizeLarge: - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPopupButtonHeight)); - break; - case QAquaSizeSmall: - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPopupButtonHeight)); - break; - case QAquaSizeMini: - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPopupButtonHeight)); - break; - default: - break; - } - break; - case QStyle::CT_ToolButton: - if (sz == QAquaSizeSmall) { - int width = 0, height = 0; - if (szHint == QSize(-1, -1)) { //just 'guess'.. -#if QT_CONFIG(toolbutton) - const QToolButton *bt = qobject_cast(widg); - // If this conversion fails then the widget was not what it claimed to be. - if(bt) { - if (!bt->icon().isNull()) { - QSize iconSize = bt->iconSize(); - QSize pmSize = bt->icon().actualSize(QSize(32, 32), QIcon::Normal); - width = qMax(width, qMax(iconSize.width(), pmSize.width())); - height = qMax(height, qMax(iconSize.height(), pmSize.height())); - } - if (!bt->text().isNull() && bt->toolButtonStyle() != Qt::ToolButtonIconOnly) { - int text_width = bt->fontMetrics().width(bt->text()), - text_height = bt->fontMetrics().height(); - if (bt->toolButtonStyle() == Qt::ToolButtonTextUnderIcon) { - width = qMax(width, text_width); - height += text_height; - } else { - width += text_width; - width = qMax(height, text_height); - } - } - } else -#endif - { - // Let's return the size hint... - width = szHint.width(); - height = szHint.height(); - } - } else { - width = szHint.width(); - height = szHint.height(); - } - width = qMax(20, width + 5); //border - height = qMax(20, height + 5); //border - ret = QSize(width, height); - } - break; - case QStyle::CT_Slider: { - int w = -1; - const QSlider *sld = qobject_cast(widg); - // If this conversion fails then the widget was not what it claimed to be. - if(sld) { - if (sz == QAquaSizeLarge) { - if (sld->orientation() == Qt::Horizontal) { - w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight); - if (sld->tickPosition() != QSlider::NoTicks) - w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight); - } else { - w = qt_mac_aqua_get_metric(kThemeMetricVSliderWidth); - if (sld->tickPosition() != QSlider::NoTicks) - w += qt_mac_aqua_get_metric(kThemeMetricVSliderTickWidth); - } - } else if (sz == QAquaSizeSmall) { - if (sld->orientation() == Qt::Horizontal) { - w = qt_mac_aqua_get_metric(kThemeMetricSmallHSliderHeight); - if (sld->tickPosition() != QSlider::NoTicks) - w += qt_mac_aqua_get_metric(kThemeMetricSmallHSliderTickHeight); - } else { - w = qt_mac_aqua_get_metric(kThemeMetricSmallVSliderWidth); - if (sld->tickPosition() != QSlider::NoTicks) - w += qt_mac_aqua_get_metric(kThemeMetricSmallVSliderTickWidth); - } - } else if (sz == QAquaSizeMini) { - if (sld->orientation() == Qt::Horizontal) { - w = qt_mac_aqua_get_metric(kThemeMetricMiniHSliderHeight); - if (sld->tickPosition() != QSlider::NoTicks) - w += qt_mac_aqua_get_metric(kThemeMetricMiniHSliderTickHeight); - } else { - w = qt_mac_aqua_get_metric(kThemeMetricMiniVSliderWidth); - if (sld->tickPosition() != QSlider::NoTicks) - w += qt_mac_aqua_get_metric(kThemeMetricMiniVSliderTickWidth); - } - } - } else { - // This is tricky, we were requested to find a size for a slider which is not - // a slider. We don't know if this is vertical or horizontal or if we need to - // have tick marks or not. - // For this case we will return an horizontal slider without tick marks. - w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight); - w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight); - } - if (sld->orientation() == Qt::Horizontal) - ret.setHeight(w); - else - ret.setWidth(w); - break; - } -#if QT_CONFIG(progressbar) - case QStyle::CT_ProgressBar: { - int finalValue = -1; - Qt::Orientation orient = Qt::Horizontal; - if (const QProgressBar *pb = qobject_cast(widg)) - orient = pb->orientation(); - - if (sz == QAquaSizeLarge) - finalValue = qt_mac_aqua_get_metric(kThemeMetricLargeProgressBarThickness) - + qt_mac_aqua_get_metric(kThemeMetricProgressBarShadowOutset); - else - finalValue = qt_mac_aqua_get_metric(kThemeMetricNormalProgressBarThickness) - + qt_mac_aqua_get_metric(kThemeMetricSmallProgressBarShadowOutset); - if (orient == Qt::Horizontal) - ret.setHeight(finalValue); - else - ret.setWidth(finalValue); - break; - } -#endif -#if QT_CONFIG(combobox) - case QStyle::CT_LineEdit: - if (!widg || !qobject_cast(widg->parentWidget())) { - //should I take into account the font dimentions of the lineedit? -Sam - if (sz == QAquaSizeLarge) - ret = QSize(-1, 21); - else - ret = QSize(-1, 19); - } - break; -#endif - case QStyle::CT_HeaderSection: -#if QT_CONFIG(treeview) - if (isTreeView(widg)) - ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight)); -#endif - break; - case QStyle::CT_MenuBar: - if (sz == QAquaSizeLarge) { - ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]); - // In the qt_mac_set_native_menubar(false) case, - // we come it here with a zero-height main menu, - // preventing the in-window menu from displaying. - // Use 22 pixels for the height, by observation. - if (ret.height() <= 0) - ret.setHeight(22); - } - break; - default: - break; - } - return ret; -} - - -#if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT) -static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSize small, QSize mini) -{ - Q_UNUSED(widg); - - if (large == QSize(-1, -1)) { - if (small != QSize(-1, -1)) - return QAquaSizeSmall; - if (mini != QSize(-1, -1)) - return QAquaSizeMini; - return QAquaSizeUnknown; - } else if (small == QSize(-1, -1)) { - if (mini != QSize(-1, -1)) - return QAquaSizeMini; - return QAquaSizeLarge; - } else if (mini == QSize(-1, -1)) { - return QAquaSizeLarge; - } - -#if QT_CONFIG(mainwindow) - if (qEnvironmentVariableIsSet("QWIDGET_ALL_SMALL")) { - //if (small.width() != -1 || small.height() != -1) - return QAquaSizeSmall; - } else if (qEnvironmentVariableIsSet("QWIDGET_ALL_MINI")) { - return QAquaSizeMini; - } -#endif - -#if 0 - /* Figure out which size we're closer to, I just hacked this in, I haven't - tested it as it would probably look pretty strange to have some widgets - big and some widgets small in the same window?? -Sam */ - int large_delta=0; - if (large.width() != -1) { - int delta = large.width() - widg->width(); - large_delta += delta * delta; - } - if (large.height() != -1) { - int delta = large.height() - widg->height(); - large_delta += delta * delta; - } - int small_delta=0; - if (small.width() != -1) { - int delta = small.width() - widg->width(); - small_delta += delta * delta; - } - if (small.height() != -1) { - int delta = small.height() - widg->height(); - small_delta += delta * delta; - } - int mini_delta=0; - if (mini.width() != -1) { - int delta = mini.width() - widg->width(); - mini_delta += delta * delta; - } - if (mini.height() != -1) { - int delta = mini.height() - widg->height(); - mini_delta += delta * delta; - } - if (mini_delta < small_delta && mini_delta < large_delta) - return QAquaSizeMini; - else if (small_delta < large_delta) - return QAquaSizeSmall; -#endif - return QAquaSizeLarge; -} -#endif - -void QMacStylePrivate::drawFocusRing(QPainter *p, const QRect &targetRect, int hMargin, int vMargin, qreal radius) const -{ - const qreal pixelRatio = p->device()->devicePixelRatioF(); - static const QString keyFormat = QLatin1String("$qt_focusring%1-%2-%3-%4"); - const QString &key = keyFormat.arg(hMargin).arg(vMargin).arg(radius).arg(pixelRatio); - QPixmap focusRingPixmap; - const qreal size = radius * 2 + 5; - - if (!QPixmapCache::find(key, focusRingPixmap)) { - focusRingPixmap = QPixmap((QSize(size, size) + 2 * QSize(hMargin, vMargin)) * pixelRatio); - focusRingPixmap.fill(Qt::transparent); - focusRingPixmap.setDevicePixelRatio(pixelRatio); - { - const CGFloat focusRingWidth = radius > 0 ? 3.5 : 6; - QMacAutoReleasePool pool; - QMacCGContext ctx(&focusRingPixmap); - CGContextBeginTransparencyLayer(ctx, NULL); - CGContextSetAlpha(ctx, 0.5); // As applied to the stroke color below - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:ctx - flipped:NO]]; - CGRect focusRingRect = CGRectMake(hMargin, vMargin, size, size); - NSBezierPath *focusRingPath; - if (radius > 0) { - const CGFloat roundedRectInset = -1.5; - focusRingPath = [NSBezierPath bezierPathWithRoundedRect:NSRectFromCGRect(CGRectInset(focusRingRect, roundedRectInset, roundedRectInset)) - xRadius:radius - yRadius:radius]; - } else { - const CGFloat outerClipInset = -focusRingWidth / 2; - NSBezierPath *focusRingClipPath = [NSBezierPath bezierPathWithRect:NSRectFromCGRect(CGRectInset(focusRingRect, outerClipInset, outerClipInset))]; - const CGFloat innerClipInset = 1; - NSBezierPath *focusRingInnerClipPath = [NSBezierPath bezierPathWithRect:NSRectFromCGRect(CGRectInset(focusRingRect, innerClipInset, innerClipInset))]; - [focusRingClipPath appendBezierPath:focusRingInnerClipPath.bezierPathByReversingPath]; - [focusRingClipPath setClip]; - focusRingPath = [NSBezierPath bezierPathWithRect:NSRectFromCGRect(focusRingRect)]; - focusRingPath.lineJoinStyle = NSRoundLineJoinStyle; - } - - focusRingPath.lineWidth = focusRingWidth; - [[NSColor keyboardFocusIndicatorColor] setStroke]; - [focusRingPath stroke]; - - CGContextEndTransparencyLayer(ctx); - [NSGraphicsContext restoreGraphicsState]; - } - QPixmapCache::insert(key, focusRingPixmap); - } - - // Add 2 for the actual ring tickness going inwards - const qreal hCornerSize = 2 + hMargin + radius; - const qreal vCornerSize = 2 + vMargin + radius; - const qreal shCornerSize = hCornerSize * pixelRatio; - const qreal svCornerSize = vCornerSize * pixelRatio; - // top-left corner - p->drawPixmap(QPointF(targetRect.left(), targetRect.top()), focusRingPixmap, - QRectF(0, 0, shCornerSize, svCornerSize)); - // top-right corner - p->drawPixmap(QPointF(targetRect.right() - hCornerSize + 1, targetRect.top()), focusRingPixmap, - QRectF(focusRingPixmap.width() - shCornerSize, 0, shCornerSize, svCornerSize)); - // bottom-left corner - p->drawPixmap(QPointF(targetRect.left(), targetRect.bottom() - vCornerSize + 1), focusRingPixmap, - QRectF(0, focusRingPixmap.height() - svCornerSize, shCornerSize, svCornerSize)); - // bottom-right corner - p->drawPixmap(QPointF(targetRect.right() - hCornerSize + 1, targetRect.bottom() - vCornerSize + 1), focusRingPixmap, - QRect(focusRingPixmap.width() - shCornerSize, focusRingPixmap.height() - svCornerSize, shCornerSize, svCornerSize)); - // top edge - p->drawPixmap(QRectF(targetRect.left() + hCornerSize, targetRect.top(), targetRect.width() - 2 * hCornerSize, vCornerSize), focusRingPixmap, - QRect(shCornerSize, 0, focusRingPixmap.width() - 2 * shCornerSize, svCornerSize)); - // bottom edge - p->drawPixmap(QRectF(targetRect.left() + hCornerSize, targetRect.bottom() - vCornerSize + 1, targetRect.width() - 2 * hCornerSize, vCornerSize), focusRingPixmap, - QRect(shCornerSize, focusRingPixmap.height() - svCornerSize, focusRingPixmap.width() - 2 * shCornerSize, svCornerSize)); - // left edge - p->drawPixmap(QRectF(targetRect.left(), targetRect.top() + vCornerSize, hCornerSize, targetRect.height() - 2 * vCornerSize), focusRingPixmap, - QRect(0, svCornerSize, shCornerSize, focusRingPixmap.width() - 2 * svCornerSize)); - // right edge - p->drawPixmap(QRectF(targetRect.right() - hCornerSize + 1, targetRect.top() + vCornerSize, hCornerSize, targetRect.height() - 2 * vCornerSize), focusRingPixmap, - QRect(focusRingPixmap.width() - shCornerSize, svCornerSize, shCornerSize, focusRingPixmap.width() - 2 * svCornerSize)); -} - -#if QT_CONFIG(tabbar) -void QMacStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const -{ - Q_ASSERT(textRect); - Q_ASSERT(iconRect); - QRect tr = opt->rect; - const bool verticalTabs = opt->shape == QTabBar::RoundedEast - || opt->shape == QTabBar::RoundedWest - || opt->shape == QTabBar::TriangularEast - || opt->shape == QTabBar::TriangularWest; - if (verticalTabs) - tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform - - int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt, widget); - int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt, widget); - const int hpadding = 4; - const int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt, widget) / 2; - if (opt->shape == QTabBar::RoundedSouth || opt->shape == QTabBar::TriangularSouth) - verticalShift = -verticalShift; - tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding); - - // left widget - if (!opt->leftButtonSize.isEmpty()) { - const int buttonSize = verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width(); - tr.setLeft(tr.left() + 4 + buttonSize); - // make text aligned to center - if (opt->rightButtonSize.isEmpty()) - tr.setRight(tr.right() - 4 - buttonSize); - } - // right widget - if (!opt->rightButtonSize.isEmpty()) { - const int buttonSize = verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width(); - tr.setRight(tr.right() - 4 - buttonSize); - // make text aligned to center - if (opt->leftButtonSize.isEmpty()) - tr.setLeft(tr.left() + 4 + buttonSize); - } - - // icon - if (!opt->icon.isNull()) { - QSize iconSize = opt->iconSize; - if (!iconSize.isValid()) { - int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize); - iconSize = QSize(iconExtent, iconExtent); - } - QSize tabIconSize = opt->icon.actualSize(iconSize, - (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled, - (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off); - // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize - tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height())); - - *iconRect = QRect(tr.left(), tr.center().y() - tabIconSize.height() / 2, - tabIconSize.width(), tabIconSize.height()); - if (!verticalTabs) - *iconRect = proxyStyle->visualRect(opt->direction, opt->rect, *iconRect); - - int stylePadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt, widget) / 2; - stylePadding -= hpadding; - - tr.setLeft(tr.left() + stylePadding + tabIconSize.width() + 4); - tr.setRight(tr.right() - stylePadding - tabIconSize.width() - 4); - } - - if (!verticalTabs) - tr = proxyStyle->visualRect(opt->direction, opt->rect, tr); - - *textRect = tr; -} -#endif // QT_CONFIG(tabbar) - -QAquaWidgetSize QMacStylePrivate::effectiveAquaSizeConstrain(const QStyleOption *option, - const QWidget *widg, - QStyle::ContentsType ct, - QSize szHint, QSize *insz) const -{ - QAquaWidgetSize sz = aquaSizeConstrain(option, widg, ct, szHint, insz); - if (sz == QAquaSizeUnknown) - return QAquaSizeLarge; - return sz; -} - -QAquaWidgetSize QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option, const QWidget *widg, - QStyle::ContentsType ct, QSize szHint, QSize *insz) const -{ -#if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT) - if (option) { - if (option->state & QStyle::State_Small) - return QAquaSizeSmall; - if (option->state & QStyle::State_Mini) - return QAquaSizeMini; - } - - if (!widg) { - if (insz) - *insz = QSize(); - if (qEnvironmentVariableIsSet("QWIDGET_ALL_SMALL")) - return QAquaSizeSmall; - if (qEnvironmentVariableIsSet("QWIDGET_ALL_MINI")) - return QAquaSizeMini; - return QAquaSizeUnknown; - } - - Q_Q(const QMacStyle); - QSize large = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeLarge), - small = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeSmall), - mini = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeMini); - bool guess_size = false; - QAquaWidgetSize ret = QAquaSizeUnknown; - QMacStyle::WidgetSizePolicy wsp = q->widgetSizePolicy(widg); - if (wsp == QMacStyle::SizeDefault) - guess_size = true; - else if (wsp == QMacStyle::SizeMini) - ret = QAquaSizeMini; - else if (wsp == QMacStyle::SizeSmall) - ret = QAquaSizeSmall; - else if (wsp == QMacStyle::SizeLarge) - ret = QAquaSizeLarge; - if (guess_size) - ret = qt_aqua_guess_size(widg, large, small, mini); - - QSize *sz = 0; - if (ret == QAquaSizeSmall) - sz = &small; - else if (ret == QAquaSizeLarge) - sz = &large; - else if (ret == QAquaSizeMini) - sz = &mini; - if (insz) - *insz = sz ? *sz : QSize(-1, -1); -#ifdef DEBUG_SIZE_CONSTRAINT - if (sz) { - const char *size_desc = "Unknown"; - if (sz == &small) - size_desc = "Small"; - else if (sz == &large) - size_desc = "Large"; - else if (sz == &mini) - size_desc = "Mini"; - qDebug("%s - %s: %s taken (%d, %d) [%d, %d]", - widg ? widg->objectName().toLatin1().constData() : "*Unknown*", - widg ? widg->metaObject()->className() : "*Unknown*", size_desc, widg->width(), widg->height(), - sz->width(), sz->height()); - } -#endif - return ret; -#else - if (insz) - *insz = QSize(); - Q_UNUSED(widg); - Q_UNUSED(ct); - Q_UNUSED(szHint); - return QAquaSizeUnknown; -#endif -} - -/** - Returns the free space awailable for contents inside the - button (and not the size of the contents itself) -*/ -HIRect QMacStylePrivate::pushButtonContentBounds(const QStyleOptionButton *btn, - const HIThemeButtonDrawInfo *bdi) const -{ - HIRect outerBounds = qt_hirectForQRect(btn->rect); - // Adjust the bounds to correct for - // carbon not calculating the content bounds fully correct - if (bdi->kind == kThemePushButton || bdi->kind == kThemePushButtonSmall){ - outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset; - outerBounds.size.height -= QMacStylePrivate::PushButtonBottomOffset; - } else if (bdi->kind == kThemePushButtonMini) { - outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset; - } - - HIRect contentBounds; - HIThemeGetButtonContentBounds(&outerBounds, bdi, &contentBounds); - return contentBounds; -} - -/** - Calculates the size of the button contents. - This includes both the text and the icon. -*/ -QSize QMacStylePrivate::pushButtonSizeFromContents(const QStyleOptionButton *btn) const -{ - Q_Q(const QMacStyle); - QSize csz(0, 0); - QSize iconSize = btn->icon.isNull() ? QSize(0, 0) - : (btn->iconSize + QSize(QMacStylePrivate::PushButtonContentPadding, 0)); - QRect textRect = btn->text.isEmpty() ? QRect(0, 0, 1, 1) - : btn->fontMetrics.boundingRect(QRect(), Qt::AlignCenter, btn->text); - csz.setWidth(iconSize.width() + textRect.width() - + ((btn->features & QStyleOptionButton::HasMenu) - ? q->proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, 0) : 0)); - csz.setHeight(qMax(iconSize.height(), textRect.height())); - return csz; -} - -/** - Checks if the actual contents of btn fits inside the free content bounds of - 'buttonKindToCheck'. Meant as a helper function for 'initHIThemePushButton' - for determining which button kind to use for drawing. -*/ -bool QMacStylePrivate::contentFitsInPushButton(const QStyleOptionButton *btn, - HIThemeButtonDrawInfo *bdi, - ThemeButtonKind buttonKindToCheck) const -{ - ThemeButtonKind tmp = bdi->kind; - bdi->kind = buttonKindToCheck; - QSize contentSize = pushButtonSizeFromContents(btn); - QRect freeContentRect = qt_qrectForHIRect(pushButtonContentBounds(btn, bdi)); - bdi->kind = tmp; - return freeContentRect.contains(QRect(freeContentRect.x(), freeContentRect.y(), - contentSize.width(), contentSize.height())); -} - -/** - Creates a HIThemeButtonDrawInfo structure that specifies the correct button - kind and other details to use for drawing the given push button. Which - button kind depends on the size of the button, the size of the contents, - explicit user style settings, etc. -*/ -void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn, - const QWidget *widget, - const ThemeDrawState tds, - HIThemeButtonDrawInfo *bdi) const -{ - ThemeDrawState tdsModified = tds; - if (btn->state & QStyle::State_On) - tdsModified = kThemeStatePressed; - bdi->version = qt_mac_hitheme_version; - bdi->state = tdsModified; - bdi->value = kThemeButtonOff; - - if (tds == kThemeStateInactive) - bdi->state = kThemeStateActive; - if (btn->state & QStyle::State_HasFocus) - bdi->adornment = kThemeAdornmentFocus; - else - bdi->adornment = kThemeAdornmentNone; - - - if (btn->features & (QStyleOptionButton::Flat)) { - bdi->kind = kThemeBevelButton; - } else { - switch (aquaSizeConstrain(btn, widget)) { - case QAquaSizeSmall: - bdi->kind = kThemePushButtonSmall; - break; - case QAquaSizeMini: - bdi->kind = kThemePushButtonMini; - break; - case QAquaSizeLarge: - // ... We should honor if the user is explicit about using the - // large button. But right now Qt will specify the large button - // as default rather than QAquaSizeUnknown. - // So we treat it like QAquaSizeUnknown - // to get the dynamic choosing of button kind. - case QAquaSizeUnknown: - // Choose the button kind that closest match the button rect, but at the - // same time displays the button contents without clipping. - bdi->kind = kThemeBevelButton; - if (btn->rect.width() >= QMacStylePrivate::BevelButtonW && btn->rect.height() >= QMacStylePrivate::BevelButtonH){ - if (widget && widget->testAttribute(Qt::WA_MacVariableSize)) { - if (btn->rect.height() <= QMacStylePrivate::MiniButtonH){ - if (contentFitsInPushButton(btn, bdi, kThemePushButtonMini)) - bdi->kind = kThemePushButtonMini; - } else if (btn->rect.height() <= QMacStylePrivate::SmallButtonH){ - if (contentFitsInPushButton(btn, bdi, kThemePushButtonSmall)) - bdi->kind = kThemePushButtonSmall; - } else if (contentFitsInPushButton(btn, bdi, kThemePushButton)) { - bdi->kind = kThemePushButton; - } - } else { - bdi->kind = kThemePushButton; - } - } - } - } -} - -#if QT_CONFIG(pushbutton) -bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option) -{ - QMacStyle *macStyle = qobject_cast(pushButton->style()); - if (!macStyle) - return false; - HIThemeButtonDrawInfo bdi; - macStyle->d_func()->initHIThemePushButton(option, pushButton, kThemeStateActive, &bdi); - return bdi.kind == kThemeBevelButton; -} -#endif - -/** - Creates a HIThemeButtonDrawInfo structure that specifies the correct button - kind and other details to use for drawing the given combobox. Which button - kind depends on the size of the combo, wether or not it is editable, - explicit user style settings, etc. -*/ -void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi, - const QWidget *widget, const ThemeDrawState &tds) const -{ - bdi->version = qt_mac_hitheme_version; - bdi->adornment = kThemeAdornmentArrowLeftArrow; - bdi->value = kThemeButtonOff; - if (combo->state & QStyle::State_HasFocus) - bdi->adornment = kThemeAdornmentFocus; - if (combo->activeSubControls & QStyle::SC_ComboBoxArrow) - bdi->state = kThemeStatePressed; - else - bdi->state = tds; - - QAquaWidgetSize aSize = aquaSizeConstrain(combo, widget); - switch (aSize) { - case QAquaSizeMini: - bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini) - : ThemeButtonKind(kThemePopupButtonMini); - break; - case QAquaSizeSmall: - bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxSmall) - : ThemeButtonKind(kThemePopupButtonSmall); - break; - case QAquaSizeUnknown: - case QAquaSizeLarge: - // Unless the user explicitly specified large buttons, determine the - // kind by looking at the combox size. - // ... specifying small and mini-buttons it not a current feature of - // Qt (e.g. QWidget::getAttribute(WA_ButtonSize)). But when it is, add - // an extra check here before using the mini and small buttons. - int h = combo->rect.size().height(); - if (combo->editable){ -#if QT_CONFIG(datetimeedit) - if (qobject_cast(widget)) { - // Except when, you know, we get a QDateTimeEdit with calendarPopup - // enabled. And then things get weird, basically because it's a - // transvestite spinbox with editable combobox tendencies. Meaning - // that it wants to look a combobox, except that it isn't one, so it - // doesn't get all those extra free margins around. (Don't know whose - // idea those margins were, but now it looks like we're stuck with - // them forever). So anyway, the height threshold should be smaller - // in this case, or the style gets confused when it needs to render - // or return any subcontrol size of the poor thing. - if (h < 9) - bdi->kind = kThemeComboBoxMini; - else if (h < 22) - bdi->kind = kThemeComboBoxSmall; - else - bdi->kind = kThemeComboBox; - } else -#endif - { - if (h < 21) - bdi->kind = kThemeComboBoxMini; - else if (h < 26) - bdi->kind = kThemeComboBoxSmall; - else - bdi->kind = kThemeComboBox; - } - } else { - // Even if we specify that we want the kThemePopupButton, Carbon - // will use the kThemePopupButtonSmall if the size matches. So we - // do the same size check explicit to have the size of the inner - // text field be correct. Therefore, do this even if the user specifies - // the use of LargeButtons explicit. - if (h < 21) - bdi->kind = kThemePopupButtonMini; - else if (h < 26) - bdi->kind = kThemePopupButtonSmall; - else - bdi->kind = kThemePopupButton; - } - break; - } -} - -/** - Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain - the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds. -*/ -HIRect QMacStylePrivate::comboboxInnerBounds(const HIRect &outerBounds, int buttonKind) -{ - HIRect innerBounds = outerBounds; - // Carbon draw parts of the view outside the rect. - // So make the rect a bit smaller to compensate - // (I wish HIThemeGetButtonBackgroundBounds worked) - switch (buttonKind){ - case kThemePopupButton: - innerBounds.origin.x += 2; - innerBounds.origin.y += 2; - innerBounds.size.width -= 5; - innerBounds.size.height -= 6; - break; - case kThemePopupButtonSmall: - innerBounds.origin.x += 3; - innerBounds.origin.y += 3; - innerBounds.size.width -= 6; - innerBounds.size.height -= 7; - break; - case kThemePopupButtonMini: - innerBounds.origin.x += 2; - innerBounds.origin.y += 2; - innerBounds.size.width -= 5; - innerBounds.size.height -= 6; - break; - case kThemeComboBox: - innerBounds.origin.x += 3; - innerBounds.origin.y += 2; - innerBounds.size.width -= 6; - innerBounds.size.height -= 8; - break; - case kThemeComboBoxSmall: - innerBounds.origin.x += 3; - innerBounds.origin.y += 3; - innerBounds.size.width -= 7; - innerBounds.size.height -= 8; - break; - case kThemeComboBoxMini: - innerBounds.origin.x += 3; - innerBounds.origin.y += 3; - innerBounds.size.width -= 4; - innerBounds.size.height -= 8; - break; - default: - break; - } - return innerBounds; -} - -/** - Inside a combobox Qt places a line edit widget. The size of this widget should depend on the kind - of combobox we choose to draw. This function calculates and returns this size. -*/ -QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi) -{ - QRect ret = outerBounds; - switch (bdi.kind){ - case kThemeComboBox: - ret.adjust(5, 5, -22, -5); - break; - case kThemeComboBoxSmall: - ret.adjust(4, 5, -18, 0); - ret.setHeight(16); - break; - case kThemeComboBoxMini: - ret.adjust(4, 5, -16, 0); - ret.setHeight(13); - break; - case kThemePopupButton: - ret.adjust(10, 2, -23, -4); - break; - case kThemePopupButtonSmall: - ret.adjust(9, 3, -20, -3); - break; - case kThemePopupButtonMini: - ret.adjust(8, 3, -19, 0); - ret.setHeight(13); - break; - } - return ret; -} - -/** - Carbon comboboxes don't scale (sight). If the size of the combo suggest a scaled version, - create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop - it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly. -*/ -void QMacStylePrivate::drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p) -{ - if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){ - // We have an unscaled combobox, or popup-button; use Carbon directly. - HIRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind); - HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0); - } else { - QPixmap buffer; - QString key = QString(QLatin1String("$qt_cbox%1-%2")).arg(int(bdi.state)).arg(int(bdi.adornment)); - if (!QPixmapCache::find(key, buffer)) { - HIRect innerBoundsSmallCombo = {{3, 3}, {29, 25}}; - buffer = QPixmap(35, 28); - buffer.fill(Qt::transparent); - QPainter buffPainter(&buffer); - HIThemeDrawButton(&innerBoundsSmallCombo, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0); - buffPainter.end(); - QPixmapCache::insert(key, buffer); - } - - const int bwidth = 20; - const int fwidth = 10; - const int fheight = 10; - int w = qRound(outerBounds.size.width); - int h = qRound(outerBounds.size.height); - int bstart = w - bwidth; - int blower = fheight + 1; - int flower = h - fheight; - int sheight = flower - fheight; - int center = qRound(outerBounds.size.height + outerBounds.origin.y) / 2; - - // Draw upper and lower gap - p->drawPixmap(fwidth, 0, bstart - fwidth, fheight, buffer, fwidth, 0, 1, fheight); - p->drawPixmap(fwidth, flower, bstart - fwidth, fheight, buffer, fwidth, buffer.height() - fheight, 1, fheight); - // Draw left and right gap. Right gap is drawn top and bottom separatly - p->drawPixmap(0, fheight, fwidth, sheight, buffer, 0, fheight, fwidth, 1); - p->drawPixmap(bstart, fheight, bwidth, center - fheight, buffer, buffer.width() - bwidth, fheight - 1, bwidth, 1); - p->drawPixmap(bstart, center, bwidth, sheight / 2, buffer, buffer.width() - bwidth, fheight + 6, bwidth, 1); - // Draw arrow - p->drawPixmap(bstart, center - 4, bwidth - 3, 6, buffer, buffer.width() - bwidth, fheight, bwidth - 3, 6); - // Draw corners - p->drawPixmap(0, 0, fwidth, fheight, buffer, 0, 0, fwidth, fheight); - p->drawPixmap(bstart, 0, bwidth, fheight, buffer, buffer.width() - bwidth, 0, bwidth, fheight); - p->drawPixmap(0, flower, fwidth, fheight, buffer, 0, buffer.height() - fheight, fwidth, fheight); - p->drawPixmap(bstart, h - blower, bwidth, blower, buffer, buffer.width() - bwidth, buffer.height() - blower, bwidth, blower); - } -} - -/** - Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header - onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget. -*/ -void QMacStylePrivate::drawTableHeader(const HIRect &outerBounds, - bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p) -{ - static SInt32 headerHeight = 0; - static OSStatus err = GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight); - Q_UNUSED(err); - - QPixmap buffer; - QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value)); - if (!QPixmapCache::find(key, buffer)) { - HIRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}}; - buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height); - buffer.fill(Qt::transparent); - QPainter buffPainter(&buffer); - HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0); - buffPainter.end(); - QPixmapCache::insert(key, buffer); - } - const int buttonw = qRound(outerBounds.size.width); - const int buttonh = qRound(outerBounds.size.height); - const int framew = 1; - const int frameh_n = 4; - const int frameh_s = 3; - const int transh = buffer.height() - frameh_n - frameh_s; - int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom; - - int skipTopBorder = 0; - if (!drawTopBorder) - skipTopBorder = 1; - - p->translate(outerBounds.origin.x, outerBounds.origin.y); - - p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n)); - p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s)); - // Draw upper and lower center blocks - p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1)); - p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1)); - // Draw right center block borders - p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1)); - p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1)); - // Draw right corners - p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n)); - p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s)); - // Draw center transition block - p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), buttonw - framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(framew, frameh_n + 1, 1, transh)); - // Draw right center transition block border - p->drawPixmap(QRect(buttonw - framew, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(buffer.width() - framew, frameh_n + 1, framew, transh)); - if (drawLeftBorder){ - // Draw left center block borders - p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1)); - p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1)); - // Draw left corners - p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n)); - p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s)); - // Draw left center transition block border - p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh)); - } - - p->translate(-outerBounds.origin.x, -outerBounds.origin.y); -} - -/* - Returns cutoff sizes for scroll bars. - thumbIndicatorCutoff is the smallest size where the thumb indicator is drawn. - scrollButtonsCutoff is the smallest size where the up/down buttons is drawn. -*/ -enum ScrollBarCutoffType { thumbIndicatorCutoff = 0, scrollButtonsCutoff = 1 }; -static int scrollButtonsCutoffSize(ScrollBarCutoffType cutoffType, QMacStyle::WidgetSizePolicy widgetSize) -{ - // Mini scroll bars do not exist as of version 10.4. - if (widgetSize == QMacStyle::SizeMini) - return 0; - - const int sizeIndex = (widgetSize == QMacStyle::SizeSmall) ? 1 : 0; - static const int sizeTable[2][2] = { { 61, 56 }, { 49, 44 } }; - return sizeTable[sizeIndex][cutoffType]; -} - -void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider, - HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe) const -{ - memset(tdi, 0, sizeof(HIThemeTrackDrawInfo)); // We don't get it all for some reason or another... - tdi->version = qt_mac_hitheme_version; - tdi->reserved = 0; - tdi->filler1 = 0; - bool isScrollbar = (cc == QStyle::CC_ScrollBar); - switch (aquaSizeConstrain(slider, needToRemoveMe)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - if (isScrollbar) - tdi->kind = kThemeMediumScrollBar; - else - tdi->kind = kThemeMediumSlider; - break; - case QAquaSizeMini: - if (isScrollbar) - tdi->kind = kThemeSmallScrollBar; // should be kThemeMiniScrollBar, but not implemented - else - tdi->kind = kThemeMiniSlider; - break; - case QAquaSizeSmall: - if (isScrollbar) - tdi->kind = kThemeSmallScrollBar; - else - tdi->kind = kThemeSmallSlider; - break; - } - - bool usePlainKnob = slider->tickPosition == QSlider::NoTicks - || slider->tickPosition == QSlider::TicksBothSides; - - tdi->bounds = qt_hirectForQRect(slider->rect); - if (isScrollbar) { - tdi->min = slider->minimum; - tdi->max = slider->maximum; - tdi->value = slider->sliderPosition; - } else { - // Fix min and max positions. HITheme seems confused when it comes to rendering - // a slider at those positions. We give it a hand by extending and offsetting - // the slider range accordingly. See also comment for CC_Slider in drawComplexControl() - tdi->min = 0; - if (slider->orientation == Qt::Horizontal) - tdi->max = 10 * slider->rect.width(); - else - tdi->max = 10 * slider->rect.height(); - - int range = slider->maximum - slider->minimum; - if (range == 0) { - tdi->value = 0; - } else if (usePlainKnob || slider->orientation == Qt::Horizontal) { - int endsCorrection = usePlainKnob ? 25 : 10; - tdi->value = (tdi->max + 2 * endsCorrection) * (slider->sliderPosition - slider->minimum) / range - endsCorrection; - } else { - tdi->value = (tdi->max + 30) * (slider->sliderPosition - slider->minimum) / range - 20; - } - } - tdi->attributes = kThemeTrackShowThumb; - if (slider->upsideDown) - tdi->attributes |= kThemeTrackRightToLeft; - if (slider->orientation == Qt::Horizontal) { - tdi->attributes |= kThemeTrackHorizontal; - if (isScrollbar && slider->direction == Qt::RightToLeft) { - if (!slider->upsideDown) - tdi->attributes |= kThemeTrackRightToLeft; - else - tdi->attributes &= ~kThemeTrackRightToLeft; - } - } - - // Tiger broke reverse scroll bars so put them back and "fake it" - if (isScrollbar && (tdi->attributes & kThemeTrackRightToLeft)) { - tdi->attributes &= ~kThemeTrackRightToLeft; - tdi->value = tdi->max - tdi->value; - } - - tdi->enableState = (slider->state & QStyle::State_Enabled) ? kThemeTrackActive - : kThemeTrackDisabled; - if (!isScrollbar) { - if (slider->state & QStyle::QStyle::State_HasFocus) - tdi->attributes |= kThemeTrackHasFocus; - if (usePlainKnob) - tdi->trackInfo.slider.thumbDir = kThemeThumbPlain; - else if (slider->tickPosition == QSlider::TicksAbove) - tdi->trackInfo.slider.thumbDir = kThemeThumbUpward; - else - tdi->trackInfo.slider.thumbDir = kThemeThumbDownward; - } else { - tdi->trackInfo.scrollbar.viewsize = slider->pageStep; - } -} - -void QMacStylePrivate::setAutoDefaultButton(QObject *button) const -{ - if (autoDefaultButton != button) { - if (QStyleAnimation *anim = animation(autoDefaultButton)) { - anim->updateTarget(); - stopAnimation(autoDefaultButton); - } - autoDefaultButton = button; - } - if (autoDefaultButton && !animation(autoDefaultButton)) - startAnimation(new QStyleAnimation(autoDefaultButton)); -} - -QMacStylePrivate::QMacStylePrivate() - : mouseDown(false), backingStoreNSView(nil) -{ - defaultButtonStart = CFAbsoluteTimeGetCurrent(); - memset(&buttonState, 0, sizeof(ButtonState)); - - if (ptrHIShapeGetBounds == 0) { - QLibrary library(QLatin1String("/System/Library/Frameworks/Carbon.framework/Carbon")); - library.setLoadHints(QLibrary::ExportExternalSymbolsHint); - ptrHIShapeGetBounds = reinterpret_cast(library.resolve("HIShapeGetBounds")); - } - -} - -QMacStylePrivate::~QMacStylePrivate() -{ - QMacAutoReleasePool pool; - Q_FOREACH (NSView *b, cocoaControls) - [b release]; -} - -ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags) -{ - ThemeDrawState tds = kThemeStateActive; - if (flags & QStyle::State_Sunken) { - tds = kThemeStatePressed; - } else if (flags & QStyle::State_Active) { - if (!(flags & QStyle::State_Enabled)) - tds = kThemeStateUnavailable; - } else { - if (flags & QStyle::State_Enabled) - tds = kThemeStateInactive; - else - tds = kThemeStateUnavailableInactive; - } - return tds; -} - -static QCocoaWidget cocoaWidgetFromHIThemeButtonKind(ThemeButtonKind kind) -{ - QCocoaWidget w; - - switch (kind) { - case kThemePopupButton: - case kThemePopupButtonSmall: - case kThemePopupButtonMini: - w.first = QCocoaPopupButton; - break; - case kThemeComboBox: - w.first = QCocoaComboBox; - break; - case kThemeArrowButton: - w.first = QCocoaArrowButton; - break; - case kThemeCheckBox: - case kThemeCheckBoxSmall: - case kThemeCheckBoxMini: - w.first = QCocoaCheckBox; - break; - case kThemeRadioButton: - case kThemeRadioButtonSmall: - case kThemeRadioButtonMini: - w.first = QCocoaRadioButton; - break; - case kThemePushButton: - case kThemePushButtonSmall: - case kThemePushButtonMini: - w.first = QCocoaPushButton; - break; - default: - break; - } - - switch (kind) { - case kThemePushButtonSmall: - case kThemePopupButtonSmall: - case kThemeCheckBoxSmall: - case kThemeRadioButtonSmall: - w.second = QAquaSizeSmall; - break; - case kThemePushButtonMini: - case kThemePopupButtonMini: - case kThemeCheckBoxMini: - case kThemeRadioButtonMini: - w.second = QAquaSizeMini; - break; - default: - w.second = QAquaSizeLarge; - break; - } - - return w; -} - -NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const -{ - NSView *bv = cocoaControls[widget]; - if (!bv) { - - if (widget.first == QCocoaPopupButton - || widget.first == QCocoaPullDownButton) - bv = [[NSPopUpButton alloc] init]; - else if (widget.first == QCocoaComboBox) - bv = [[NSComboBox alloc] init]; - else if (widget.first == QCocoaHorizontalSlider) - bv = [[NSSlider alloc] init]; - else if (widget.first == QCocoaVerticalSlider) - // Cocoa sets the orientation from the view's frame - // at construction time, and it cannot be changed later. - bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 10, 100)]; - else - bv = [[NSButton alloc] init]; - - switch (widget.first) { - case QCocoaArrowButton: { - NSButton *bc = (NSButton *)bv; - bc.buttonType = NSOnOffButton; - bc.bezelStyle = NSDisclosureBezelStyle; - break; - } - case QCocoaCheckBox: { - NSButton *bc = (NSButton *)bv; - bc.buttonType = NSSwitchButton; - break; - } - case QCocoaRadioButton: { - NSButton *bc = (NSButton *)bv; - bc.buttonType = NSRadioButton; - break; - } - case QCocoaPushButton: { - NSButton *bc = (NSButton *)bv; - bc.buttonType = NSMomentaryLightButton; - bc.bezelStyle = NSRoundedBezelStyle; - break; - } - case QCocoaPullDownButton: { - NSPopUpButton *bc = (NSPopUpButton *)bv; - bc.pullsDown = YES; - break; - } - default: - break; - } - - if ([bv isKindOfClass:[NSButton class]]) { - NSButton *bc = (NSButton *)bv; - bc.title = @""; - } - - if ([bv isKindOfClass:[NSControl class]]) { - NSCell *bcell = [(NSControl *)bv cell]; - switch (widget.second) { - case QAquaSizeSmall: - bcell.controlSize = NSSmallControlSize; - break; - case QAquaSizeMini: - bcell.controlSize = NSMiniControlSize; - break; - default: - break; - } - } - - const_cast(this)->cocoaControls.insert(widget, bv); - } - - return bv; -} - -void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &qtRect, QPainter *p, bool isQWidget, QCocoaDrawRectBlock drawRectBlock) const -{ - QPoint offset; - if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeLarge)) - offset.setY(2); - else if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeSmall)) - offset = QPoint(-1, 2); - else if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeMini)) - offset.setY(2); - else if (widget == QCocoaWidget(QCocoaPopupButton, QAquaSizeSmall) - || widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeLarge)) - offset.setY(1); - else if (widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeSmall)) - offset.setX(-1); - else if (widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeMini)) - offset = QPoint(7, 5); - else if (widget == QCocoaWidget(QCocoaPopupButton, QAquaSizeMini)) - offset = QPoint(2, -1); - else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeLarge)) - offset = isQWidget ? QPoint(3, -1) : QPoint(-1, -3); - else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeSmall)) - offset = QPoint(2, 1); - else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeMini)) - offset = QPoint(5, 0); - else if (widget == QCocoaWidget(QCocoaComboBox, QAquaSizeLarge)) - offset = QPoint(3, 0); - - QMacCGContext ctx(p); - CGContextSaveGState(ctx); - CGContextTranslateCTM(ctx, offset.x(), offset.y()); - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:[NSGraphicsContext - graphicsContextWithGraphicsPort:ctx flipped:YES]]; - - NSRect rect = NSMakeRect(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height()); - - [backingStoreNSView addSubview:view]; - view.frame = rect; - if (drawRectBlock) - drawRectBlock(rect, (CGContextRef)ctx); - else - [view drawRect:rect]; - [view removeFromSuperviewWithoutNeedingDisplay]; - - [NSGraphicsContext restoreGraphicsState]; - CGContextRestoreGState(ctx); -} - -void QMacStylePrivate::resolveCurrentNSView(QWindow *window) -{ - backingStoreNSView = window ? (NSView *)window->winId() : nil; -} - -void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi, - QPainter *p, const QStyleOption *opt) const -{ - int xoff = 0, - yoff = 0, - extraWidth = 0, - extraHeight = 0, - finalyoff = 0; - - const bool combo = opt->type == QStyleOption::SO_ComboBox; - const bool editableCombo = bdi->kind == kThemeComboBox - || bdi->kind == kThemeComboBoxSmall - || bdi->kind == kThemeComboBoxMini; - const bool button = opt->type == QStyleOption::SO_Button; - const bool viewItem = opt->type == QStyleOption::SO_ViewItem; - const bool pressed = bdi->state == kThemeStatePressed; - - if (button && pressed) { - if (bdi->kind == kThemePushButton) { - extraHeight = 2; - } else if (bdi->kind == kThemePushButtonSmall) { - xoff = 1; - extraWidth = 2; - extraHeight = 5; - } - } - - int devicePixelRatio = p->device()->devicePixelRatioF(); - int width = devicePixelRatio * (int(macRect.size.width) + extraWidth); - int height = devicePixelRatio * (int(macRect.size.height) + extraHeight); - - if (width <= 0 || height <= 0) - return; // nothing to draw - - QString key = QLatin1String("$qt_mac_style_ctb_") + QString::number(bdi->kind) + QLatin1Char('_') - + QString::number(bdi->value) + QLatin1Char('_') - + (button ? QString::number(bdi->state) + QLatin1Char('_') : QString()) - + QLatin1Char('_') + QString::number(width) + QLatin1Char('_') + QString::number(height); - QPixmap pm; - if (!QPixmapCache::find(key, pm)) { - QPixmap activePixmap(width, height); - activePixmap.setDevicePixelRatio(devicePixelRatio); - activePixmap.fill(Qt::transparent); - { - if (combo){ - // Carbon combos don't scale. Therefore we draw it - // ourselves, if a scaled version is needed. - QPainter tmpPainter(&activePixmap); - QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter); - } else { - QMacCGContext cg(&activePixmap); - HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height); - if (button && pressed) - bdi->state = kThemeStateActive; - else if (viewItem) - bdi->state = kThemeStateInactive; - HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0); - } - } - - if (!combo && !button && bdi->value == kThemeButtonOff) { - pm = activePixmap; - } else if ((combo && !editableCombo) || button) { - QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi->kind); - NSButton *bc = (NSButton *)cocoaControl(cw); - [bc highlight:pressed]; - bc.enabled = bdi->state != kThemeStateUnavailable && bdi->state != kThemeStateUnavailableInactive; - bc.allowsMixedState = YES; - bc.state = bdi->value == kThemeButtonOn ? NSOnState : - bdi->value == kThemeButtonMixed ? NSMixedState : NSOffState; - // The view frame may differ from what we pass to HITheme - QRect rect = opt->rect; - if (bdi->kind == kThemePopupButtonMini) - rect.adjust(0, 0, -5, 0); - drawNSViewInRect(cw, bc, rect, p); - return; - } else if (editableCombo || viewItem) { - QImage image = activePixmap.toImage(); - - for (int y = 0; y < height; ++y) { - QRgb *scanLine = reinterpret_cast(image.scanLine(y)); - - for (int x = 0; x < width; ++x) { - QRgb &pixel = scanLine[x]; - int gray = qRed(pixel); // We know the image is grayscale - int alpha = qAlpha(pixel); - - if (gray == 128 && alpha == 128) { - pixel = qRgba(255, 255, 255, 255); - } else if (alpha == 0) { - pixel = 0; - } else { - bool belowThreshold = (alpha * gray) / 255 + 255 - alpha < 128; - gray = belowThreshold ? 0 : 2 * gray - 255; - alpha = belowThreshold ? 0 : 2 * alpha - 255; - pixel = qRgba(gray, gray, gray, alpha); - } - } - } - pm = QPixmap::fromImage(image); - } else { - QImage activeImage = activePixmap.toImage(); - QImage colorlessImage; - { - QPixmap colorlessPixmap(width, height); - colorlessPixmap.setDevicePixelRatio(devicePixelRatio); - colorlessPixmap.fill(Qt::transparent); - - QMacCGContext cg(&colorlessPixmap); - HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height); - int oldValue = bdi->value; - bdi->value = kThemeButtonOff; - HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0); - bdi->value = oldValue; - colorlessImage = colorlessPixmap.toImage(); - } - - for (int y = 0; y < height; ++y) { - QRgb *colorlessScanLine = reinterpret_cast(colorlessImage.scanLine(y)); - const QRgb *activeScanLine = reinterpret_cast(activeImage.scanLine(y)); - - for (int x = 0; x < width; ++x) { - QRgb &colorlessPixel = colorlessScanLine[x]; - QRgb activePixel = activeScanLine[x]; - - if (activePixel != colorlessPixel) { - int max = qMax(qMax(qRed(activePixel), qGreen(activePixel)), - qBlue(activePixel)); - QRgb newPixel = qRgba(max, max, max, qAlpha(activePixel)); - if (qGray(newPixel) < qGray(colorlessPixel) - || qAlpha(newPixel) > qAlpha(colorlessPixel)) - colorlessPixel = newPixel; - } - } - } - pm = QPixmap::fromImage(colorlessImage); - } - QPixmapCache::insert(key, pm); - } - p->drawPixmap(int(macRect.origin.x) - xoff, int(macRect.origin.y) + finalyoff, width / devicePixelRatio, height / devicePixelRatio , pm); -} - -QMacStyle::QMacStyle() - : QCommonStyle(*new QMacStylePrivate) -{ - Q_D(QMacStyle); - QMacAutoReleasePool pool; - - d->receiver = [[NotificationReceiver alloc] initWithPrivate:d]; - NotificationReceiver *receiver = static_cast(d->receiver); - - [[NSNotificationCenter defaultCenter] addObserver:receiver - selector:@selector(scrollBarStyleDidChange:) - name:NSPreferredScrollerStyleDidChangeNotification - object:nil]; - - // Create scroller objects. Scroller internal direction setup happens - // on initWithFrame and cannot be changed later on. Create two scrollers - // initialized with fake geometry. Correct geometry is set at draw time. - d->horizontalScroller = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)]; - d->verticalScroller = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)]; - - d->indicatorBranchButtonCell = nil; -} - -QMacStyle::~QMacStyle() -{ - Q_D(QMacStyle); - QMacAutoReleasePool pool; - - [d->horizontalScroller release]; - [d->verticalScroller release]; - - NotificationReceiver *receiver = static_cast(d->receiver); - [[NSNotificationCenter defaultCenter] removeObserver:receiver]; - [receiver release]; - - delete qt_mac_backgroundPattern; - qt_mac_backgroundPattern = 0; -} - -/*! \internal - Generates the standard widget background pattern. -*/ -QPixmap QMacStylePrivate::generateBackgroundPattern() const -{ - QMacAutoReleasePool pool; - QPixmap px(4, 4); - QMacCGContext cg(&px); - HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationNormal); - const CGRect cgRect = CGRectMake(0, 0, px.width(), px.height()); - CGContextFillRect(cg, cgRect); - return px; -} - -/*! \internal - Fills the given \a rect with the pattern stored in \a brush. As an optimization, - HIThemeSetFill us used directly if we are filling with the standard background. -*/ -void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush) -{ -#if 0 - QPoint dummy; - const QPaintDevice *target = painter->device(); - const QPaintDevice *redirected = QPainter::redirected(target, &dummy); - //const bool usePainter = redirected && redirected != target; - - if (!usePainter && qt_mac_backgroundPattern - && qt_mac_backgroundPattern->cacheKey() == brush.texture().cacheKey()) { - - painter->setClipRegion(rgn); - - QMacCGContext cg(target); - CGContextSaveGState(cg); - HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted); - - for (const QRect &rect : rgn) { - // Anchor the pattern to the top so it stays put when the window is resized. - CGContextSetPatternPhase(cg, CGSizeMake(rect.width(), rect.height())); - CGRect mac_rect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()); - CGContextFillRect(cg, mac_rect); - } - - CGContextRestoreGState(cg); - } else { -#endif - const QRect rect(rgn.boundingRect()); - painter->setClipRegion(rgn); - painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); -// } -} - -void QMacStyle::polish(QPalette &pal) -{ - Q_D(QMacStyle); - if (!qt_mac_backgroundPattern) { - if (!qApp) - return; - qt_mac_backgroundPattern = new QPixmap(d->generateBackgroundPattern()); - } - - - QCFString theme; - const OSErr err = CopyThemeIdentifier(&theme); - if (err == noErr && CFStringCompare(theme, kThemeAppearanceAquaGraphite, 0) == kCFCompareEqualTo) { - pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(240, 240, 240)); - } else { - pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(237, 243, 254)); - } -} - -void QMacStyle::polish(QApplication *) -{ -} - -void QMacStyle::unpolish(QApplication *) -{ -} - -void QMacStyle::polish(QWidget* w) -{ - if (qt_mac_is_metal(w) && !w->testAttribute(Qt::WA_SetPalette)) { - // Set a clear brush so that the metal shines through. - QPalette pal = w->palette(); - QBrush background(Qt::transparent); - pal.setBrush(QPalette::All, QPalette::Window, background); - pal.setBrush(QPalette::All, QPalette::Button, background); - w->setPalette(pal); - w->setAttribute(Qt::WA_SetPalette, false); - } - -#if QT_CONFIG(menu) - if (qobject_cast(w) -#if QT_CONFIG(combobox) - || qobject_cast(w) -#endif - ) { - w->setWindowOpacity(0.985); - if (!w->testAttribute(Qt::WA_SetPalette)) { - QPixmap px(64, 64); - px.fill(Qt::white); - HIThemeMenuDrawInfo mtinfo; - mtinfo.version = qt_mac_hitheme_version; - mtinfo.menuType = kThemeMenuTypePopUp; - // HIRect rect = CGRectMake(0, 0, px.width(), px.height()); - // ### - //HIThemeDrawMenuBackground(&rect, &mtinfo, QMacCGContext(&px)), - // kHIThemeOrientationNormal); - QPalette pal = w->palette(); - QBrush background(px); - pal.setBrush(QPalette::All, QPalette::Window, background); - pal.setBrush(QPalette::All, QPalette::Button, background); - w->setPalette(pal); - w->setAttribute(Qt::WA_SetPalette, false); - } - } -#endif - -#if QT_CONFIG(tabbar) - if (QTabBar *tb = qobject_cast(w)) { - if (tb->documentMode()) { - w->setAttribute(Qt::WA_Hover); - w->setFont(qt_app_fonts_hash()->value("QSmallFont", QFont())); - QPalette p = w->palette(); - p.setColor(QPalette::WindowText, QColor(17, 17, 17)); - w->setPalette(p); - w->setAttribute(Qt::WA_SetPalette, false); - w->setAttribute(Qt::WA_SetFont, false); - } - } -#endif - - QCommonStyle::polish(w); - - if (QRubberBand *rubber = qobject_cast(w)) { - rubber->setWindowOpacity(0.25); - rubber->setAttribute(Qt::WA_PaintOnScreen, false); - rubber->setAttribute(Qt::WA_NoSystemBackground, false); - } - - if (qobject_cast(w)) { - w->setAttribute(Qt::WA_OpaquePaintEvent, false); - w->setAttribute(Qt::WA_Hover, true); - w->setMouseTracking(true); - } -} - -void QMacStyle::unpolish(QWidget* w) -{ - if (( -#if QT_CONFIG(menu) - qobject_cast(w) || -#endif - qt_mac_is_metal(w) - ) && !w->testAttribute(Qt::WA_SetPalette)) { - QPalette pal = qApp->palette(w); - w->setPalette(pal); - w->setAttribute(Qt::WA_SetPalette, false); - w->setWindowOpacity(1.0); - } - -#if QT_CONFIG(combobox) - if (QComboBox *combo = qobject_cast(w)) { - if (!combo->isEditable()) { - if (QWidget *widget = combo->findChild()) - widget->setWindowOpacity(1.0); - } - } -#endif - -#if QT_CONFIG(tabbar) - if (qobject_cast(w)) { - if (!w->testAttribute(Qt::WA_SetFont)) - w->setFont(qApp->font(w)); - if (!w->testAttribute(Qt::WA_SetPalette)) - w->setPalette(qApp->palette(w)); - } -#endif - - if (QRubberBand *rubber = qobject_cast(w)) { - rubber->setWindowOpacity(1.0); - rubber->setAttribute(Qt::WA_PaintOnScreen, true); - rubber->setAttribute(Qt::WA_NoSystemBackground, true); - } - - if (QFocusFrame *frame = qobject_cast(w)) - frame->setAttribute(Qt::WA_NoSystemBackground, true); - - QCommonStyle::unpolish(w); - - if (qobject_cast(w)) { - w->setAttribute(Qt::WA_OpaquePaintEvent, true); - w->setAttribute(Qt::WA_Hover, false); - w->setMouseTracking(false); - } -} - -int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const -{ - Q_D(const QMacStyle); - int controlSize = getControlSize(opt, widget); - SInt32 ret = 0; - - switch (metric) { - case PM_TabCloseIndicatorWidth: - case PM_TabCloseIndicatorHeight: - ret = closeButtonSize; - break; - case PM_ToolBarIconSize: - ret = proxy()->pixelMetric(PM_LargeIconSize); - break; - case PM_FocusFrameVMargin: - case PM_FocusFrameHMargin: - GetThemeMetric(kThemeMetricFocusRectOutset, &ret); - break; - case PM_DialogButtonsSeparator: - ret = -5; - break; - case PM_DialogButtonsButtonHeight: { - QSize sz; - ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz); - if (sz == QSize(-1, -1)) - ret = 32; - else - ret = sz.height(); - break; } - case PM_DialogButtonsButtonWidth: { - QSize sz; - ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz); - if (sz == QSize(-1, -1)) - ret = 70; - else - ret = sz.width(); - break; } - - case PM_MenuBarHMargin: - ret = 8; - break; - - case PM_MenuBarVMargin: - ret = 0; - break; - - case PM_MenuBarPanelWidth: - ret = 0; - break; - - case QStyle::PM_MenuDesktopFrameWidth: - ret = 5; - break; - - case PM_CheckBoxLabelSpacing: - case PM_RadioButtonLabelSpacing: - ret = 2; - break; - case PM_MenuScrollerHeight: -#if 0 - SInt16 ash, asw; - GetThemeMenuItemExtra(kThemeMenuItemScrollUpArrow, &ash, &asw); - ret = ash; -#else - ret = 15; // I hate having magic numbers in here... -#endif - break; - case PM_DefaultFrameWidth: -#if QT_CONFIG(mainwindow) - if (widget && (widget->isWindow() || !widget->parentWidget() - || (qobject_cast(widget->parentWidget()) - && static_cast(widget->parentWidget())->centralWidget() == widget)) - && qobject_cast(widget)) - ret = 0; - else -#endif - // The combo box popup has no frame. - if (qstyleoption_cast(opt) != 0) - ret = 0; - else - ret = 1; - break; - case PM_MaximumDragDistance: - ret = -1; - break; - case PM_ScrollBarSliderMin: - ret = 24; - break; - case PM_SpinBoxFrameWidth: - GetThemeMetric(kThemeMetricEditTextFrameOutset, &ret); - switch (d->aquaSizeConstrain(opt, widget)) { - default: - ret += 2; - break; - case QAquaSizeMini: - ret += 1; - break; - } - break; - case PM_ButtonShiftHorizontal: - case PM_ButtonShiftVertical: - ret = 0; - break; - case PM_SliderLength: - ret = 17; - break; - // Returns the number of pixels to use for the business part of the - // slider (i.e., the non-tickmark portion). The remaining space is shared - // equally between the tickmark regions. - case PM_SliderControlThickness: - if (const QStyleOptionSlider *sl = qstyleoption_cast(opt)) { - int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width(); - int ticks = sl->tickPosition; - int n = 0; - if (ticks & QSlider::TicksAbove) - ++n; - if (ticks & QSlider::TicksBelow) - ++n; - if (!n) { - ret = space; - break; - } - - int thick = 6; // Magic constant to get 5 + 16 + 5 - if (ticks != QSlider::TicksBothSides && ticks != QSlider::NoTicks) - thick += proxy()->pixelMetric(PM_SliderLength, sl, widget) / 4; - - space -= thick; - if (space > 0) - thick += (space * 2) / (n + 2); - ret = thick; - } else { - ret = 0; - } - break; - case PM_SmallIconSize: - ret = int(QStyleHelper::dpiScaled(16.)); - break; - - case PM_LargeIconSize: - ret = int(QStyleHelper::dpiScaled(32.)); - break; - - case PM_IconViewIconSize: - ret = proxy()->pixelMetric(PM_LargeIconSize, opt, widget); - break; - - case PM_ButtonDefaultIndicator: - ret = 0; - break; - case PM_TitleBarHeight: { - NSUInteger style = NSTitledWindowMask; - if (widget && ((widget->windowFlags() & Qt::Tool) == Qt::Tool)) - style |= NSUtilityWindowMask; - ret = int([NSWindow frameRectForContentRect:NSZeroRect - styleMask:style].size.height); - break; } - case QStyle::PM_TabBarTabHSpace: - switch (d->aquaSizeConstrain(opt, widget)) { - case QAquaSizeLarge: - ret = QCommonStyle::pixelMetric(metric, opt, widget); - break; - case QAquaSizeSmall: - ret = 20; - break; - case QAquaSizeMini: - ret = 16; - break; - case QAquaSizeUnknown: - const QStyleOptionTab *tb = qstyleoption_cast(opt); - if (tb && tb->documentMode) - ret = 30; - else - ret = QCommonStyle::pixelMetric(metric, opt, widget); - break; - } - break; - case PM_TabBarTabVSpace: - ret = 4; - break; - case PM_TabBarTabShiftHorizontal: - case PM_TabBarTabShiftVertical: - ret = 0; - break; - case PM_TabBarBaseHeight: - ret = 0; - break; - case PM_TabBarTabOverlap: - ret = 1; - break; - case PM_TabBarBaseOverlap: - switch (d->aquaSizeConstrain(opt, widget)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - ret = 11; - break; - case QAquaSizeSmall: - ret = 8; - break; - case QAquaSizeMini: - ret = 7; - break; - } - break; - case PM_ScrollBarExtent: { - const QAquaWidgetSize size = d->effectiveAquaSizeConstrain(opt, widget); - ret = static_cast([NSScroller - scrollerWidthForControlSize:static_cast(size) - scrollerStyle:[NSScroller preferredScrollerStyle]]); - break; } - case PM_IndicatorHeight: { - switch (d->aquaSizeConstrain(opt, widget)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - GetThemeMetric(kThemeMetricCheckBoxHeight, &ret); - break; - case QAquaSizeMini: - GetThemeMetric(kThemeMetricMiniCheckBoxHeight, &ret); - break; - case QAquaSizeSmall: - GetThemeMetric(kThemeMetricSmallCheckBoxHeight, &ret); - break; - } - break; } - case PM_IndicatorWidth: { - switch (d->aquaSizeConstrain(opt, widget)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - GetThemeMetric(kThemeMetricCheckBoxWidth, &ret); - break; - case QAquaSizeMini: - GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret); - break; - case QAquaSizeSmall: - GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret); - break; - } - ++ret; - break; } - case PM_ExclusiveIndicatorHeight: { - switch (d->aquaSizeConstrain(opt, widget)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - GetThemeMetric(kThemeMetricRadioButtonHeight, &ret); - break; - case QAquaSizeMini: - GetThemeMetric(kThemeMetricMiniRadioButtonHeight, &ret); - break; - case QAquaSizeSmall: - GetThemeMetric(kThemeMetricSmallRadioButtonHeight, &ret); - break; - } - break; } - case PM_ExclusiveIndicatorWidth: { - switch (d->aquaSizeConstrain(opt, widget)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - GetThemeMetric(kThemeMetricRadioButtonWidth, &ret); - break; - case QAquaSizeMini: - GetThemeMetric(kThemeMetricMiniRadioButtonWidth, &ret); - break; - case QAquaSizeSmall: - GetThemeMetric(kThemeMetricSmallRadioButtonWidth, &ret); - break; - } - ++ret; - break; } - case PM_MenuVMargin: - ret = 4; - break; - case PM_MenuPanelWidth: - ret = 0; - break; - case PM_ToolTipLabelFrameWidth: - ret = 0; - break; - case PM_SizeGripSize: { - QAquaWidgetSize aSize; - if (widget && widget->window()->windowType() == Qt::Tool) - aSize = QAquaSizeSmall; - else - aSize = QAquaSizeLarge; - const QSize size = qt_aqua_get_known_size(CT_SizeGrip, widget, QSize(), aSize); - ret = size.width(); - break; } - case PM_MdiSubWindowFrameWidth: - ret = 1; - break; - case PM_DockWidgetFrameWidth: - ret = 0; - break; - case PM_DockWidgetTitleMargin: - ret = 0; - break; - case PM_DockWidgetSeparatorExtent: - ret = 1; - break; - case PM_ToolBarHandleExtent: - ret = 11; - break; - case PM_ToolBarItemMargin: - ret = 0; - break; - case PM_ToolBarItemSpacing: - ret = 4; - break; - case PM_SplitterWidth: - ret = qMax(7, QApplication::globalStrut().width()); - break; - case PM_LayoutLeftMargin: - case PM_LayoutTopMargin: - case PM_LayoutRightMargin: - case PM_LayoutBottomMargin: - { - bool isWindow = false; - if (opt) { - isWindow = (opt->state & State_Window); - } else if (widget) { - isWindow = widget->isWindow(); - } - - if (isWindow) { - bool isMetal = widget && widget->testAttribute(Qt::WA_MacBrushedMetal); - if (isMetal) { - if (metric == PM_LayoutTopMargin) { - return_SIZE(9 /* AHIG */, 6 /* guess */, 6 /* guess */); - } else if (metric == PM_LayoutBottomMargin) { - return_SIZE(18 /* AHIG */, 15 /* guess */, 13 /* guess */); - } else { - return_SIZE(14 /* AHIG */, 11 /* guess */, 9 /* guess */); - } - } else { - /* - AHIG would have (20, 8, 10) here but that makes - no sense. It would also have 14 for the top margin - but this contradicts both Builder and most - applications. - */ - return_SIZE(20, 10, 10); // AHIG - } - } else { - // hack to detect QTabWidget - if (widget && widget->parentWidget() - && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) { - if (metric == PM_LayoutTopMargin) { - /* - Builder would have 14 (= 20 - 6) instead of 12, - but that makes the tab look disproportionate. - */ - return_SIZE(12, 6, 6); // guess - } else { - return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */); - } - } else { - /* - Child margins are highly inconsistent in AHIG and Builder. - */ - return_SIZE(12, 8, 6); // guess - } - } - } - case PM_LayoutHorizontalSpacing: - case PM_LayoutVerticalSpacing: - return -1; - case PM_MenuHMargin: - ret = 0; - break; - case PM_ToolBarExtensionExtent: - ret = 21; - break; - case PM_ToolBarFrameWidth: - ret = 1; - break; - case PM_ScrollView_ScrollBarOverlap: - ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay ? - pixelMetric(PM_ScrollBarExtent, opt, widget) : 0; - break; - default: - ret = QCommonStyle::pixelMetric(metric, opt, widget); - break; - } - return ret; -} - -QPalette QMacStyle::standardPalette() const -{ - QPalette pal = QCommonStyle::standardPalette(); - pal.setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191)); - pal.setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191)); - pal.setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191)); - return pal; -} - -int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w, - QStyleHintReturn *hret) const -{ - QMacAutoReleasePool pool; - - SInt32 ret = 0; - switch (sh) { - case SH_Slider_SnapToValue: - case SH_PrintDialog_RightAlignButtons: - case SH_FontDialog_SelectAssociatedText: - case SH_MenuBar_MouseTracking: - case SH_Menu_MouseTracking: - case SH_ComboBox_ListMouseTracking: - case SH_MainWindow_SpaceBelowMenuBar: - case SH_ItemView_ChangeHighlightOnFocus: - ret = 1; - break; - case SH_ToolBox_SelectedPageTitleBold: - ret = 0; - break; - case SH_DialogButtonBox_ButtonsHaveIcons: - ret = 0; - break; - case SH_Menu_SelectionWrap: - ret = false; - break; - case SH_Menu_KeyboardSearch: - ret = true; - break; - case SH_Menu_SpaceActivatesItem: - ret = true; - break; - case SH_Slider_AbsoluteSetButtons: - ret = Qt::LeftButton|Qt::MidButton; - break; - case SH_Slider_PageSetButtons: - ret = 0; - break; - case SH_ScrollBar_ContextMenu: - ret = false; - break; - case SH_TitleBar_AutoRaise: - ret = true; - break; - case SH_Menu_AllowActiveAndDisabled: - ret = false; - break; - case SH_Menu_SubMenuPopupDelay: - ret = 100; - break; - case SH_Menu_SubMenuUniDirection: - ret = true; - break; - case SH_Menu_SubMenuSloppySelectOtherActions: - ret = false; - break; - case SH_Menu_SubMenuResetWhenReenteringParent: - ret = true; - break; - case SH_Menu_SubMenuDontStartSloppyOnLeave: - ret = true; - break; - - case SH_ScrollBar_LeftClickAbsolutePosition: { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - bool result = [defaults boolForKey:@"AppleScrollerPagingBehavior"]; - if(QApplication::keyboardModifiers() & Qt::AltModifier) - ret = !result; - else - ret = result; - break; } - case SH_TabBar_PreferNoArrows: - ret = true; - break; - /* - case SH_DialogButtons_DefaultButton: - ret = QDialogButtons::Reject; - break; - */ - case SH_GroupBox_TextLabelVerticalAlignment: - ret = Qt::AlignTop; - break; - case SH_ScrollView_FrameOnlyAroundContents: - ret = QCommonStyle::styleHint(sh, opt, w, hret); - break; - case SH_Menu_FillScreenWithScroll: - ret = false; - break; - case SH_Menu_Scrollable: - ret = true; - break; - case SH_RichText_FullWidthSelection: - ret = true; - break; - case SH_BlinkCursorWhenTextSelected: - ret = false; - break; - case SH_ScrollBar_StopMouseOverSlider: - ret = true; - break; - case SH_ListViewExpand_SelectMouseType: - ret = QEvent::MouseButtonRelease; - break; - case SH_TabBar_SelectMouseType: -#if QT_CONFIG(tabbar) - if (const QStyleOptionTabBarBase *opt2 = qstyleoption_cast(opt)) { - ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease; - } else -#endif - { - ret = QEvent::MouseButtonRelease; - } - break; - case SH_ComboBox_Popup: - if (const QStyleOptionComboBox *cmb = qstyleoption_cast(opt)) - ret = !cmb->editable; - else - ret = 0; - break; - case SH_Workspace_FillSpaceOnMaximize: - ret = true; - break; - case SH_Widget_ShareActivation: - ret = true; - break; - case SH_Header_ArrowAlignment: - ret = Qt::AlignRight; - break; - case SH_TabBar_Alignment: { -#if QT_CONFIG(tabwidget) - if (const QTabWidget *tab = qobject_cast(w)) { - if (tab->documentMode()) { - ret = Qt::AlignLeft; - break; - } - } -#endif -#if QT_CONFIG(tabbar) - if (const QTabBar *tab = qobject_cast(w)) { - if (tab->documentMode()) { - ret = Qt::AlignLeft; - break; - } - } -#endif - ret = Qt::AlignCenter; - } break; - case SH_UnderlineShortcut: - ret = false; - break; - case SH_ToolTipLabel_Opacity: - ret = 242; // About 95% - break; - case SH_Button_FocusPolicy: - ret = Qt::TabFocus; - break; - case SH_EtchDisabledText: - ret = false; - break; - case SH_FocusFrame_Mask: { - ret = true; - if(QStyleHintReturnMask *mask = qstyleoption_cast(hret)) { - const uchar fillR = 192, fillG = 191, fillB = 190; - QImage img; - - QSize pixmapSize = opt->rect.size(); - if (!pixmapSize.isEmpty()) { - QPixmap pix(pixmapSize); - pix.fill(QColor(fillR, fillG, fillB)); - QPainter pix_paint(&pix); - proxy()->drawControl(CE_FocusFrame, opt, &pix_paint, w); - pix_paint.end(); - img = pix.toImage(); - } - - const QRgb *sptr = (QRgb*)img.bits(), *srow; - const int sbpl = img.bytesPerLine(); - const int w = sbpl/4, h = img.height(); - - QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32); - QRgb *dptr = (QRgb*)img_mask.bits(), *drow; - const int dbpl = img_mask.bytesPerLine(); - - for (int y = 0; y < h; ++y) { - srow = sptr+((y*sbpl)/4); - drow = dptr+((y*dbpl)/4); - for (int x = 0; x < w; ++x) { - const int redDiff = qRed(*srow) - fillR; - const int greenDiff = qGreen(*srow) - fillG; - const int blueDiff = qBlue(*srow) - fillB; - const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff); - (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000; - ++srow; - } - } - QBitmap qmask = QBitmap::fromImage(img_mask); - mask->region = QRegion(qmask); - } - break; } - case SH_TitleBar_NoBorder: - ret = 1; - break; - case SH_RubberBand_Mask: - ret = 0; - break; - case SH_ComboBox_LayoutDirection: - ret = Qt::LeftToRight; - break; - case SH_ItemView_EllipsisLocation: - ret = Qt::AlignHCenter; - break; - case SH_ItemView_ShowDecorationSelected: - ret = true; - break; - case SH_TitleBar_ModifyNotification: - ret = false; - break; - case SH_ScrollBar_RollBetweenButtons: - ret = true; - break; - case SH_WindowFrame_Mask: - ret = 1; - if (QStyleHintReturnMask *mask = qstyleoption_cast(hret)) { - mask->region = opt->rect; - mask->region -= QRect(opt->rect.left(), opt->rect.top(), 5, 1); - mask->region -= QRect(opt->rect.left(), opt->rect.top() + 1, 3, 1); - mask->region -= QRect(opt->rect.left(), opt->rect.top() + 2, 2, 1); - mask->region -= QRect(opt->rect.left(), opt->rect.top() + 3, 1, 2); - - mask->region -= QRect(opt->rect.right() - 4, opt->rect.top(), 5, 1); - mask->region -= QRect(opt->rect.right() - 2, opt->rect.top() + 1, 3, 1); - mask->region -= QRect(opt->rect.right() - 1, opt->rect.top() + 2, 2, 1); - mask->region -= QRect(opt->rect.right() , opt->rect.top() + 3, 1, 2); - } - break; - case SH_TabBar_ElideMode: - ret = Qt::ElideRight; - break; -#if QT_CONFIG(dialogbuttonbox) - case SH_DialogButtonLayout: - ret = QDialogButtonBox::MacLayout; - break; -#endif - case SH_FormLayoutWrapPolicy: - ret = QFormLayout::DontWrapRows; - break; - case SH_FormLayoutFieldGrowthPolicy: - ret = QFormLayout::FieldsStayAtSizeHint; - break; - case SH_FormLayoutFormAlignment: - ret = Qt::AlignHCenter | Qt::AlignTop; - break; - case SH_FormLayoutLabelAlignment: - ret = Qt::AlignRight; - break; - case SH_ComboBox_PopupFrameStyle: - ret = QFrame::NoFrame | QFrame::Plain; - break; - case SH_MessageBox_TextInteractionFlags: - ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard; - break; - case SH_SpellCheckUnderlineStyle: - ret = QTextCharFormat::DashUnderline; - break; - case SH_MessageBox_CenterButtons: - ret = false; - break; - case SH_MenuBar_AltKeyNavigation: - ret = false; - break; - case SH_ItemView_MovementWithoutUpdatingSelection: - ret = false; - break; - case SH_FocusFrame_AboveWidget: - ret = true; - break; -#if QT_CONFIG(wizard) - case SH_WizardStyle: - ret = QWizard::MacStyle; - break; -#endif - case SH_ItemView_ArrowKeysNavigateIntoChildren: - ret = false; - break; - case SH_Menu_FlashTriggeredItem: - ret = true; - break; - case SH_Menu_FadeOutOnHide: - ret = true; - break; - case SH_Menu_Mask: - if (opt) { - if (QStyleHintReturnMask *mask = qstyleoption_cast(hret)) { - ret = true; - HIRect menuRect = CGRectMake(opt->rect.x(), opt->rect.y() + 4, - opt->rect.width(), opt->rect.height() - 8); - HIThemeMenuDrawInfo mdi; - mdi.version = 0; -#if QT_CONFIG(menu) - if (w && qobject_cast(w->parentWidget())) - mdi.menuType = kThemeMenuTypeHierarchical; - else -#endif - mdi.menuType = kThemeMenuTypePopUp; - QCFType shape; - HIThemeGetMenuBackgroundShape(&menuRect, &mdi, &shape); - - mask->region = qt_mac_fromHIShapeRef(shape); - } - } - break; - case SH_ItemView_PaintAlternatingRowColorsForEmptyArea: - ret = true; - break; -#if QT_CONFIG(tabbar) - case SH_TabBar_CloseButtonPosition: - ret = QTabBar::LeftSide; - break; -#endif - case SH_DockWidget_ButtonsHaveFrame: - ret = false; - break; - case SH_ScrollBar_Transient: - if ((qobject_cast(w) && w->parent() && - qobject_cast(w->parent()->parent())) -#ifndef QT_NO_ACCESSIBILITY - || (opt && QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ScrollBar)) -#endif - ) { - ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay; - } - break; - case SH_ItemView_ScrollMode: - ret = QAbstractItemView::ScrollPerPixel; - break; - default: - ret = QCommonStyle::styleHint(sh, opt, w, hret); - break; - } - return ret; -} - -QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, - const QStyleOption *opt) const -{ - switch (iconMode) { - case QIcon::Disabled: { - QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); - int imgh = img.height(); - int imgw = img.width(); - QRgb pixel; - for (int y = 0; y < imgh; ++y) { - for (int x = 0; x < imgw; ++x) { - pixel = img.pixel(x, y); - img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), - qAlpha(pixel) / 2)); - } - } - return QPixmap::fromImage(img); - } - default: - ; - } - return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt); -} - - -QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, - const QWidget *widget) const -{ - // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap() - // I don't want infinite recursion so if we do get in that situation, just return the Window's - // standard pixmap instead (since there is no mac-specific icon then). This should be fine until - // someone changes how Windows standard - // pixmap works. - static bool recursionGuard = false; - - if (recursionGuard) - return QCommonStyle::standardPixmap(standardPixmap, opt, widget); - - recursionGuard = true; - QIcon icon = proxy()->standardIcon(standardPixmap, opt, widget); - recursionGuard = false; - int size; - switch (standardPixmap) { - default: - size = 32; - break; - case SP_MessageBoxCritical: - case SP_MessageBoxQuestion: - case SP_MessageBoxInformation: - case SP_MessageBoxWarning: - size = 64; - break; - } - return icon.pixmap(qt_getWindow(widget), QSize(size, size)); -} - -void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy) -{ - QWidget *wadget = const_cast(widget); - wadget->setAttribute(Qt::WA_MacNormalSize, policy == SizeLarge); - wadget->setAttribute(Qt::WA_MacSmallSize, policy == SizeSmall); - wadget->setAttribute(Qt::WA_MacMiniSize, policy == SizeMini); -} - -QMacStyle::WidgetSizePolicy QMacStyle::widgetSizePolicy(const QWidget *widget, const QStyleOption *opt) -{ - while (widget) { - if (widget->testAttribute(Qt::WA_MacMiniSize)) { - return SizeMini; - } else if (widget->testAttribute(Qt::WA_MacSmallSize)) { - return SizeSmall; - } else if (widget->testAttribute(Qt::WA_MacNormalSize)) { - return SizeLarge; - } - widget = widget->parentWidget(); - } - - if (opt && opt->state & State_Mini) - return SizeMini; - else if (opt && opt->state & State_Small) - return SizeSmall; - - return SizeDefault; -} - -void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, - const QWidget *w) const -{ - Q_D(const QMacStyle); - ThemeDrawState tds = d->getDrawState(opt->state); - QMacCGContext cg(p); - QWindow *window = w && w->window() ? w->window()->windowHandle() : - QStyleHelper::styleObjectWindow(opt->styleObject); - const_cast(d)->resolveCurrentNSView(window); - switch (pe) { - case PE_IndicatorArrowUp: - case PE_IndicatorArrowDown: - case PE_IndicatorArrowRight: - case PE_IndicatorArrowLeft: { - p->save(); - p->setRenderHint(QPainter::Antialiasing); - int xOffset = opt->direction == Qt::LeftToRight ? 2 : -1; - QMatrix matrix; - matrix.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2); - QPainterPath path; - switch(pe) { - default: - case PE_IndicatorArrowDown: - break; - case PE_IndicatorArrowUp: - matrix.rotate(180); - break; - case PE_IndicatorArrowLeft: - matrix.rotate(90); - break; - case PE_IndicatorArrowRight: - matrix.rotate(-90); - break; - } - path.moveTo(0, 5); - path.lineTo(-4, -3); - path.lineTo(4, -3); - p->setMatrix(matrix); - p->setPen(Qt::NoPen); - p->setBrush(QColor(0, 0, 0, 135)); - p->drawPath(path); - p->restore(); - break; } -#if QT_CONFIG(tabbar) - case PE_FrameTabBarBase: - if (const QStyleOptionTabBarBase *tbb - = qstyleoption_cast(opt)) { - if (tbb->documentMode) { - p->save(); - drawTabBase(p, tbb, w); - p->restore(); - return; - } - - QRegion region(tbb->rect); - region -= tbb->tabBarRect; - p->save(); - p->setClipRegion(region); - QStyleOptionTabWidgetFrame twf; - twf.QStyleOption::operator=(*tbb); - twf.shape = tbb->shape; - switch (getTabDirection(twf.shape)) { - case kThemeTabNorth: - twf.rect = twf.rect.adjusted(0, 0, 0, 10); - break; - case kThemeTabSouth: - twf.rect = twf.rect.adjusted(0, -10, 0, 0); - break; - case kThemeTabWest: - twf.rect = twf.rect.adjusted(0, 0, 10, 0); - break; - case kThemeTabEast: - twf.rect = twf.rect.adjusted(0, -10, 0, 0); - break; - } - proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p, w); - p->restore(); - } - break; -#endif - case PE_PanelTipLabel: - p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase)); - break; - case PE_FrameGroupBox: - if (const QStyleOptionFrame *groupBox = qstyleoption_cast(opt)) { - if (groupBox->features & QStyleOptionFrame::Flat) { - QCommonStyle::drawPrimitive(pe, groupBox, p, w); - } else { - HIThemeGroupBoxDrawInfo gdi; - gdi.version = qt_mac_hitheme_version; - gdi.state = tds; -#if QT_CONFIG(groupbox) - if (w && qobject_cast(w->parentWidget())) - gdi.kind = kHIThemeGroupBoxKindSecondary; - else -#endif - gdi.kind = kHIThemeGroupBoxKindPrimary; - HIRect hirect = qt_hirectForQRect(opt->rect); - HIThemeDrawGroupBox(&hirect, &gdi, cg, kHIThemeOrientationNormal); - } - } - break; - case PE_IndicatorToolBarSeparator: { - QPainterPath path; - if (opt->state & State_Horizontal) { - int xpoint = opt->rect.center().x(); - path.moveTo(xpoint + 0.5, opt->rect.top() + 1); - path.lineTo(xpoint + 0.5, opt->rect.bottom()); - } else { - int ypoint = opt->rect.center().y(); - path.moveTo(opt->rect.left() + 2 , ypoint + 0.5); - path.lineTo(opt->rect.right() + 1, ypoint + 0.5); - } - QPainterPathStroker theStroker; - theStroker.setCapStyle(Qt::FlatCap); - theStroker.setDashPattern(QVector() << 1 << 2); - path = theStroker.createStroke(path); - p->fillPath(path, QColor(0, 0, 0, 119)); - } - break; - case PE_FrameWindow: - break; - case PE_IndicatorDockWidgetResizeHandle: { - // The docwidget resize handle is drawn as a one-pixel wide line. - p->save(); - if (opt->state & State_Horizontal) { - p->setPen(QColor(160, 160, 160)); - p->drawLine(opt->rect.topLeft(), opt->rect.topRight()); - } else { - p->setPen(QColor(145, 145, 145)); - p->drawLine(opt->rect.topRight(), opt->rect.bottomRight()); - } - p->restore(); - } break; - case PE_IndicatorToolBarHandle: { - p->save(); - QPainterPath path; - int x = opt->rect.x() + 6; - int y = opt->rect.y() + 7; - static const int RectHeight = 2; - if (opt->state & State_Horizontal) { - while (y < opt->rect.height() - RectHeight - 5) { - path.moveTo(x, y); - path.addEllipse(x, y, RectHeight, RectHeight); - y += 6; - } - } else { - while (x < opt->rect.width() - RectHeight - 5) { - path.moveTo(x, y); - path.addEllipse(x, y, RectHeight, RectHeight); - x += 6; - } - } - p->setPen(Qt::NoPen); - QColor dark = opt->palette.dark().color().darker(); - dark.setAlphaF(0.50); - p->fillPath(path, dark); - p->restore(); - - break; - } - case PE_IndicatorHeaderArrow: - if (const QStyleOptionHeader *header = qstyleoption_cast(opt)) { - // In HITheme, up is down, down is up and hamburgers eat people. - if (header->sortIndicator != QStyleOptionHeader::None) - proxy()->drawPrimitive( - (header->sortIndicator == QStyleOptionHeader::SortDown) ? - PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w); - } - break; - case PE_IndicatorMenuCheckMark: { - QColor pc; - if (opt->state & State_On) - pc = opt->palette.highlightedText().color(); - else - pc = opt->palette.text().color(); - - QCFType checkmarkColor = CGColorCreateGenericRGB(static_cast(pc.redF()), - static_cast(pc.greenF()), - static_cast(pc.blueF()), - static_cast(pc.alphaF())); - // kCTFontUIFontSystem and others give the same result - // as kCTFontUIFontMenuItemMark. However, the latter is - // more reminiscent to HITheme's kThemeMenuItemMarkFont. - // See also the font for small- and mini-sized widgets, - // where we end up using the generic system font type. - const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem : - (opt->state & State_Small) ? kCTFontUIFontSmallSystem : - kCTFontUIFontMenuItemMark; - // Similarly for the font size, where there is a small difference - // between regular combobox and item view items, and and menu items. - // However, we ignore any difference for small- and mini-sized widgets. - const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0; - QCFType checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL); - - CGContextSaveGState(cg); - CGContextSetShouldSmoothFonts(cg, NO); // Same as HITheme and Cocoa menu checkmarks - - // Baseline alignment tweaks for QComboBox and QMenu - const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 : - (opt->state & State_Small) ? 1.0 : - 0.75; - - CGContextTranslateCTM(cg, 0, opt->rect.bottom()); - CGContextScaleCTM(cg, 1, -1); - // Translate back to the original position and add rect origin and offset - CGContextTranslateCTM(cg, opt->rect.x(), vOffset); - - // CTFont has severe difficulties finding the checkmark character among its - // glyphs. Fortunately, CTLine knows its ways inside the Cocoa labyrinth. - static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName }; - static const int numValues = sizeof(keys) / sizeof(keys[0]); - const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor }; - Q_STATIC_ASSERT((sizeof(values) / sizeof(values[0])) == numValues); - QCFType attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, - numValues, NULL, NULL); - // U+2713: CHECK MARK - QCFType checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@"\u2713", attributes); - QCFType line = CTLineCreateWithAttributedString(checkmarkString); - - CTLineDraw((CTLineRef)line, cg); - CGContextFlush(cg); // CTLineDraw's documentation says it doesn't flush - - CGContextRestoreGState(cg); - break; } - case PE_IndicatorViewItemCheck: - case PE_IndicatorRadioButton: - case PE_IndicatorCheckBox: { - bool drawColorless = tds == kThemeStateInactive; - HIThemeButtonDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - bdi.state = tds; - if (drawColorless) - bdi.state = kThemeStateActive; - bdi.adornment = kThemeDrawIndicatorOnly; - if (opt->state & State_HasFocus) - bdi.adornment |= kThemeAdornmentFocus; - bool isRadioButton = (pe == PE_IndicatorRadioButton); - switch (d->aquaSizeConstrain(opt, w)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - if (isRadioButton) - bdi.kind = kThemeRadioButton; - else - bdi.kind = kThemeCheckBox; - break; - case QAquaSizeMini: - if (isRadioButton) - bdi.kind = kThemeMiniRadioButton; - else - bdi.kind = kThemeMiniCheckBox; - break; - case QAquaSizeSmall: - if (isRadioButton) - bdi.kind = kThemeSmallRadioButton; - else - bdi.kind = kThemeSmallCheckBox; - break; - } - if (opt->state & State_NoChange) - bdi.value = kThemeButtonMixed; - else if (opt->state & State_On) - bdi.value = kThemeButtonOn; - else - bdi.value = kThemeButtonOff; - HIRect macRect = qt_hirectForQRect(opt->rect); - if (!drawColorless) - HIThemeDrawButton(&macRect, &bdi, cg, kHIThemeOrientationNormal, 0); - else - d->drawColorlessButton(macRect, &bdi, p, opt); - break; } - case PE_FrameFocusRect: - // Use the our own focus widget stuff. - break; - case PE_IndicatorBranch: { - if (!(opt->state & State_Children)) - break; - if (!d->indicatorBranchButtonCell) - const_cast(d)->indicatorBranchButtonCell = (void *)[[NSButtonCell alloc] init]; - NSButtonCell *triangleCell = (NSButtonCell *)d->indicatorBranchButtonCell; - [triangleCell setButtonType:NSOnOffButton]; - [triangleCell setState:(opt->state & State_Open) ? NSOnState : NSOffState]; - [triangleCell setBezelStyle:NSDisclosureBezelStyle]; - bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus); - [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleDark : NSBackgroundStyleLight]; - - CGContextSaveGState(cg); - [NSGraphicsContext saveGraphicsState]; - - [NSGraphicsContext setCurrentContext:[NSGraphicsContext - graphicsContextWithGraphicsPort:(CGContextRef)cg flipped:NO]]; - - QRect qtRect = opt->rect.adjusted(DisclosureOffset, 0, -DisclosureOffset, 0); - CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height()); - CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height); - CGContextScaleCTM(cg, 1, -1); - CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y); - - [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]]; - - [NSGraphicsContext restoreGraphicsState]; - CGContextRestoreGState(cg); - break; } - - case PE_Frame: { - QPen oldPen = p->pen(); - p->setPen(opt->palette.base().color().darker(140)); - p->drawRect(opt->rect.adjusted(0, 0, -1, -1)); - p->setPen(opt->palette.base().color().darker(180)); - p->drawLine(opt->rect.topLeft(), opt->rect.topRight()); - p->setPen(oldPen); - break; } - - case PE_FrameLineEdit: - if (const QStyleOptionFrame *frame = qstyleoption_cast(opt)) { - if (frame->state & State_Sunken) { - QColor baseColor(frame->palette.background().color()); - HIThemeFrameDrawInfo fdi; - fdi.version = qt_mac_hitheme_version; - fdi.state = tds; - SInt32 frame_size; - fdi.kind = frame->features & QStyleOptionFrame::Rounded ? kHIThemeFrameTextFieldRound : - kHIThemeFrameTextFieldSquare; - GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size); - if ((frame->state & State_ReadOnly) || !(frame->state & State_Enabled)) - fdi.state = kThemeStateInactive; - else if (fdi.state == kThemeStatePressed) - // This pressed state doesn't make sense for a line edit frame. - // And Yosemite agrees with us. Otherwise it starts showing yellow pixels. - fdi.state = kThemeStateActive; - fdi.isFocused = (frame->state & State_HasFocus); - int lw = frame->lineWidth; - if (lw <= 0) - lw = proxy()->pixelMetric(PM_DefaultFrameWidth, frame, w); - { //clear to base color - p->save(); - p->setPen(QPen(baseColor, lw)); - p->setBrush(Qt::NoBrush); - p->drawRect(frame->rect); - p->restore(); - } - HIRect hirect = qt_hirectForQRect(frame->rect, - QRect(frame_size, frame_size, - frame_size * 2, frame_size * 2)); - - HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal); - } else { - QCommonStyle::drawPrimitive(pe, opt, p, w); - } - } - break; - case PE_PanelLineEdit: - QCommonStyle::drawPrimitive(pe, opt, p, w); - // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit). - // Focus frame is drawn outside the rectangle passed in the option-rect. - if (const QStyleOptionFrame *panel = qstyleoption_cast(opt)) { -#if QT_CONFIG(lineedit) - if ((opt->state & State_HasFocus) && !qobject_cast(w)) { - int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin); - int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin); - QStyleOptionFrame focusFrame = *panel; - focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin); - drawControl(CE_FocusFrame, &focusFrame, p, w); - } -#endif - } - - break; -#if QT_CONFIG(tabwidget) - case PE_FrameTabWidget: - if (const QStyleOptionTabWidgetFrame *twf - = qstyleoption_cast(opt)) { - HIRect hirect = qt_hirectForQRect(twf->rect); - HIThemeTabPaneDrawInfo tpdi; - tpdi.version = qt_mac_hitheme_tab_version(); - tpdi.state = tds; - tpdi.direction = getTabDirection(twf->shape); - tpdi.size = kHIThemeTabSizeNormal; - tpdi.kind = kHIThemeTabKindNormal; - tpdi.adornment = kHIThemeTabPaneAdornmentNormal; - HIThemeDrawTabPane(&hirect, &tpdi, cg, kHIThemeOrientationNormal); - } - break; -#endif - case PE_PanelScrollAreaCorner: { - const QBrush brush(opt->palette.brush(QPalette::Base)); - p->fillRect(opt->rect, brush); - p->setPen(QPen(QColor(217, 217, 217))); - p->drawLine(opt->rect.topLeft(), opt->rect.topRight()); - p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft()); - } break; - case PE_FrameStatusBarItem: - break; - case PE_IndicatorTabClose: { - // Make close button visible only on the hovered tab. - if (QTabBar *tabBar = qobject_cast(w->parentWidget())) { - const bool documentMode = tabBar->documentMode(); - const QTabBarPrivate *tabBarPrivate = static_cast(QObjectPrivate::get(tabBar)); - const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex(); - if (!documentMode || - (hoveredTabIndex != -1 && ((w == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) || - (w == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) { - const bool hover = (opt->state & State_MouseOver); - const bool selected = (opt->state & State_Selected); - const bool pressed = (opt->state & State_Sunken); - drawTabCloseButton(p, hover, selected, pressed, documentMode); - } - } - } break; - case PE_PanelStatusBar: { - // Fill the status bar with the titlebar gradient. - QLinearGradient linearGrad; - if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active)) { - linearGrad = titlebarGradientActive(); - } else { - linearGrad = titlebarGradientInactive(); - } - - linearGrad.setStart(0, opt->rect.top()); - linearGrad.setFinalStop(0, opt->rect.bottom()); - p->fillRect(opt->rect, linearGrad); - - // Draw the black separator line at the top of the status bar. - if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active)) - p->setPen(titlebarSeparatorLineActive); - else - p->setPen(titlebarSeparatorLineInactive); - p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top()); - - break; - } - - default: - QCommonStyle::drawPrimitive(pe, opt, p, w); - break; - } -} - -static inline QPixmap darkenPixmap(const QPixmap &pixmap) -{ - QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32); - int imgh = img.height(); - int imgw = img.width(); - int h, s, v, a; - QRgb pixel; - for (int y = 0; y < imgh; ++y) { - for (int x = 0; x < imgw; ++x) { - pixel = img.pixel(x, y); - a = qAlpha(pixel); - QColor hsvColor(pixel); - hsvColor.getHsv(&h, &s, &v); - s = qMin(100, s * 2); - v = v / 2; - hsvColor.setHsv(h, s, v); - pixel = hsvColor.rgb(); - img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a)); - } - } - return QPixmap::fromImage(img); -} - - - -void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p, - const QWidget *w) const -{ - Q_D(const QMacStyle); - ThemeDrawState tds = d->getDrawState(opt->state); - QMacCGContext cg(p); - QWindow *window = w && w->window() ? w->window()->windowHandle() : - QStyleHelper::styleObjectWindow(opt->styleObject); - const_cast(d)->resolveCurrentNSView(window); - switch (ce) { - case CE_HeaderSection: - if (const QStyleOptionHeader *header = qstyleoption_cast(opt)) { - HIThemeButtonDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - State flags = header->state; - QRect ir = header->rect; - bdi.kind = kThemeListHeaderButton; - bdi.adornment = kThemeAdornmentNone; - bdi.state = kThemeStateActive; - - if (flags & State_On) - bdi.value = kThemeButtonOn; - else - bdi.value = kThemeButtonOff; - - if (header->orientation == Qt::Horizontal){ - switch (header->position) { - case QStyleOptionHeader::Beginning: - ir.adjust(-1, -1, 0, 0); - break; - case QStyleOptionHeader::Middle: - ir.adjust(-1, -1, 0, 0); - break; - case QStyleOptionHeader::OnlyOneSection: - case QStyleOptionHeader::End: - ir.adjust(-1, -1, 1, 0); - break; - default: - break; - } - - if (header->position != QStyleOptionHeader::Beginning - && header->position != QStyleOptionHeader::OnlyOneSection) { - bdi.adornment = header->direction == Qt::LeftToRight - ? kThemeAdornmentHeaderButtonLeftNeighborSelected - : kThemeAdornmentHeaderButtonRightNeighborSelected; - } - } - - if (flags & State_Active) { - if (!(flags & State_Enabled)) - bdi.state = kThemeStateUnavailable; - else if (flags & State_Sunken) - bdi.state = kThemeStatePressed; - } else { - if (flags & State_Enabled) - bdi.state = kThemeStateInactive; - else - bdi.state = kThemeStateUnavailableInactive; - } - - if (header->sortIndicator != QStyleOptionHeader::None) { - bdi.value = kThemeButtonOn; - if (header->sortIndicator == QStyleOptionHeader::SortDown) - bdi.adornment = kThemeAdornmentHeaderButtonSortUp; - } - if (flags & State_HasFocus) - bdi.adornment = kThemeAdornmentFocus; - - ir = visualRect(header->direction, header->rect, ir); - HIRect bounds = qt_hirectForQRect(ir); - - bool noVerticalHeader = true; -#if QT_CONFIG(tableview) - if (w) - if (const QTableView *table = qobject_cast(w->parentWidget())) - noVerticalHeader = !table->verticalHeader()->isVisible(); -#endif - - bool drawTopBorder = header->orientation == Qt::Horizontal; - bool drawLeftBorder = header->orientation == Qt::Vertical - || header->position == QStyleOptionHeader::OnlyOneSection - || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader); - d->drawTableHeader(bounds, drawTopBorder, drawLeftBorder, bdi, p); - } - break; - case CE_HeaderLabel: - if (const QStyleOptionHeader *header = qstyleoption_cast(opt)) { - p->save(); - QRect textr = header->rect; - if (!header->icon.isNull()) { - QIcon::Mode mode = QIcon::Disabled; - if (opt->state & State_Enabled) - mode = QIcon::Normal; - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); - QPixmap pixmap = header->icon.pixmap(window, QSize(iconExtent, iconExtent), mode); - - QRect pixr = header->rect; - pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2); - proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap); - textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0); - } - - proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette, - header->state & State_Enabled, header->text, QPalette::ButtonText); - p->restore(); - } - break; - case CE_ToolButtonLabel: - if (const QStyleOptionToolButton *tb = qstyleoption_cast(opt)) { - QStyleOptionToolButton myTb = *tb; - myTb.state &= ~State_AutoRaise; -#ifndef QT_NO_ACCESSIBILITY - if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) { - QRect cr = tb->rect; - int shiftX = 0; - int shiftY = 0; - bool needText = false; - int alignment = 0; - bool down = tb->state & (State_Sunken | State_On); - if (down) { - shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, w); - shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb, w); - } - // The down state is special for QToolButtons in a toolbar on the Mac - // The text is a bit bolder and gets a drop shadow and the icons are also darkened. - // This doesn't really fit into any particular case in QIcon, so we - // do the majority of the work ourselves. - if (!(tb->features & QStyleOptionToolButton::Arrow)) { - Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle; - if (tb->icon.isNull() && !tb->text.isEmpty()) - tbstyle = Qt::ToolButtonTextOnly; - - switch (tbstyle) { - case Qt::ToolButtonTextOnly: { - needText = true; - alignment = Qt::AlignCenter; - break; } - case Qt::ToolButtonIconOnly: - case Qt::ToolButtonTextBesideIcon: - case Qt::ToolButtonTextUnderIcon: { - QRect pr = cr; - QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal - : QIcon::Disabled; - QIcon::State iconState = (tb->state & State_On) ? QIcon::On - : QIcon::Off; - QPixmap pixmap = tb->icon.pixmap(window, - tb->rect.size().boundedTo(tb->iconSize), - iconMode, iconState); - - // Draw the text if it's needed. - if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) { - needText = true; - if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { - pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6); - cr.adjust(0, pr.bottom(), 0, -3); - alignment |= Qt::AlignCenter; - } else { - pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8); - cr.adjust(pr.right(), 0, 0, 0); - alignment |= Qt::AlignLeft | Qt::AlignVCenter; - } - } - if (opt->state & State_Sunken) { - pr.translate(shiftX, shiftY); - pixmap = darkenPixmap(pixmap); - } - proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap); - break; } - default: - Q_ASSERT(false); - break; - } - - if (needText) { - QPalette pal = tb->palette; - QPalette::ColorRole role = QPalette::NoRole; - if (!proxy()->styleHint(SH_UnderlineShortcut, tb, w)) - alignment |= Qt::TextHideMnemonic; - if (down) - cr.translate(shiftX, shiftY); - if (tbstyle == Qt::ToolButtonTextOnly - || (tbstyle != Qt::ToolButtonTextOnly && !down)) { - QPen pen = p->pen(); - QColor light = down ? Qt::black : Qt::white; - light.setAlphaF(0.375f); - p->setPen(light); - p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text); - p->setPen(pen); - if (down && tbstyle == Qt::ToolButtonTextOnly) { - pal = QApplication::palette("QMenu"); - pal.setCurrentColorGroup(tb->palette.currentColorGroup()); - role = QPalette::HighlightedText; - } - } - proxy()->drawItemText(p, cr, alignment, pal, - tb->state & State_Enabled, tb->text, role); - } - } else { - QCommonStyle::drawControl(ce, &myTb, p, w); - } - } else { - QCommonStyle::drawControl(ce, &myTb, p, w); - } -#else - Q_UNUSED(tb) -#endif - } - break; - case CE_ToolBoxTabShape: - QCommonStyle::drawControl(ce, opt, p, w); - break; - case CE_PushButtonBevel: - if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { - if (!(btn->state & (State_Raised | State_Sunken | State_On))) - break; - - if (btn->features & QStyleOptionButton::CommandLinkButton) { - QCommonStyle::drawControl(ce, opt, p, w); - break; - } - - // No default button pulsating animation on Yosemite, - // so we have to do few things differently. - - // a focused auto-default button within an active window - // takes precedence over a normal default button - if (btn->features & QStyleOptionButton::AutoDefaultButton - && opt->state & State_Active && opt->state & State_HasFocus) { - d->autoDefaultButton = opt->styleObject; - } else if (d->autoDefaultButton == opt->styleObject) { - d->setAutoDefaultButton(0); - } - - if (!d->autoDefaultButton) { - if (btn->features & QStyleOptionButton::DefaultButton && opt->state & State_Active) { - d->defaultButton = opt->styleObject; - } else if (d->defaultButton == opt->styleObject) { - if (QStyleAnimation *animation = d->animation(opt->styleObject)) { - animation->updateTarget(); - d->stopAnimation(opt->styleObject); - } - d->defaultButton = 0; - } - } - - // TODO: find out the pressed button in a qwidget independent way - extern QWidget *qt_button_down; // qwidgetwindow.cpp - if (opt->styleObject == qt_button_down) - d->pressedButton = opt->styleObject; - else if (d->pressedButton == opt->styleObject) - d->pressedButton = 0; - - bool hasMenu = btn->features & QStyleOptionButton::HasMenu; - HIThemeButtonDrawInfo bdi; - d->initHIThemePushButton(btn, w, tds, &bdi); - - if (!hasMenu) { - // HITheme is not drawing a nice focus frame around buttons. - // We'll do it ourselves further down. - bdi.adornment &= ~kThemeAdornmentFocus; - - // We can't rely on an animation existing to test for the default look. That means a bit - // more logic (notice that the logic is slightly different for the bevel and the label). - if (tds == kThemeStateActive - && (btn->features & QStyleOptionButton::DefaultButton - || (btn->features & QStyleOptionButton::AutoDefaultButton - && d->autoDefaultButton == btn->styleObject))) - bdi.adornment |= kThemeAdornmentDefault; - } - - // Unlike Carbon, we want the button to always be drawn inside its bounds. - // Therefore, make the button a bit smaller, so that even if it got focus, - // the focus 'shadow' will be inside. - HIRect newRect = qt_hirectForQRect(btn->rect); - if (bdi.kind == kThemePushButton || bdi.kind == kThemePushButtonSmall) { - newRect.origin.x += QMacStylePrivate::PushButtonLeftOffset; - newRect.origin.y += QMacStylePrivate::PushButtonTopOffset; - newRect.size.width -= QMacStylePrivate::PushButtonRightOffset; - newRect.size.height -= QMacStylePrivate::PushButtonBottomOffset; - } else if (bdi.kind == kThemePushButtonMini) { - newRect.origin.x += QMacStylePrivate::PushButtonLeftOffset - 2; - newRect.origin.y += QMacStylePrivate::PushButtonTopOffset; - newRect.size.width -= QMacStylePrivate::PushButtonRightOffset - 4; - } - - if (hasMenu && bdi.kind != kThemeBevelButton) { - QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind); - cw.first = QCocoaPullDownButton; - NSPopUpButton *pdb = (NSPopUpButton *)d->cocoaControl(cw); - [pdb highlight:(bdi.state == kThemeStatePressed)]; - pdb.enabled = bdi.state != kThemeStateUnavailable && bdi.state != kThemeStateUnavailableInactive; - QRect rect = opt->rect; - rect.adjust(0, 0, cw.second == QAquaSizeSmall ? -4 : cw.second == QAquaSizeMini ? -9 : -6, 0); - d->drawNSViewInRect(cw, pdb, rect, p, w != 0); - } else if (hasMenu && bdi.state == kThemeStatePressed) - d->drawColorlessButton(newRect, &bdi, p, opt); - else - HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0); - - if (btn->state & State_HasFocus) { - CGRect focusRect = newRect; - if (bdi.kind == kThemePushButton) - focusRect.size.height += 1; // Another thing HITheme and Cocoa seem to disagree about. - else if (bdi.kind == kThemePushButtonMini) - focusRect.size.height = 15; // Our QPushButton sizes are really weird - - if (bdi.adornment & kThemeAdornmentDefault || bdi.state == kThemeStatePressed) { - if (bdi.kind == kThemePushButtonSmall) { - focusRect = CGRectInset(focusRect, -1, 0); - } else if (bdi.kind == kThemePushButtonMini) { - focusRect = CGRectInset(focusRect, 1, 0); - } - } else { - if (bdi.kind == kThemePushButton) { - focusRect = CGRectInset(focusRect, 1, 1); - } else if (bdi.kind == kThemePushButtonSmall) { - focusRect = CGRectInset(focusRect, 0, 2); - } else if (bdi.kind == kThemePushButtonMini) { - focusRect = CGRectInset(focusRect, 2, 1); - } - } - - const qreal radius = bdi.kind == kThemeBevelButton ? 0 : 4; - const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, btn, w); - const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, btn, w); - const QRect focusTargetRect(focusRect.origin.x, focusRect.origin.y, focusRect.size.width, focusRect.size.height); - d->drawFocusRing(p, focusTargetRect.adjusted(-hMargin, -vMargin, hMargin, vMargin), hMargin, vMargin, radius); - } - - if (hasMenu && bdi.kind == kThemeBevelButton) { - int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w); - QRect ir = btn->rect; - int arrowXOffset = bdi.kind == kThemePushButton ? 6 : - bdi.kind == kThemePushButtonSmall ? 7 : 8; - int arrowYOffset = bdi.kind == kThemePushButton ? 3 : - bdi.kind == kThemePushButtonSmall ? 1 : 2; - if (!w) { - // adjustment for Qt Quick Controls - arrowYOffset -= ir.top(); - if (bdi.kind == kThemePushButtonSmall) - arrowYOffset += 1; - } - QRect ar = QRect(ir.right() - mbi - QMacStylePrivate::PushButtonRightOffset, - ir.height() / 2 - arrowYOffset, mbi, ir.height() / 2); - ar = visualRect(btn->direction, ir, ar); - HIRect arrowRect = CGRectMake(ar.x() + arrowXOffset, ar.y(), ar.width(), ar.height()); - - HIThemePopupArrowDrawInfo pdi; - pdi.version = qt_mac_hitheme_version; - pdi.state = tds == kThemeStateInactive ? kThemeStateActive : tds; - pdi.orientation = kThemeArrowDown; - if (bdi.kind == kThemePushButtonMini) - pdi.size = kThemeArrow5pt; - else if (bdi.kind == kThemePushButton || bdi.kind == kThemePushButtonSmall) - pdi.size = kThemeArrow7pt; - HIThemeDrawPopupArrow(&arrowRect, &pdi, cg, kHIThemeOrientationNormal); - } - } - break; - case CE_PushButtonLabel: - if (const QStyleOptionButton *b = qstyleoption_cast(opt)) { - QStyleOptionButton btn(*b); - // We really don't want the label to be drawn the same as on - // windows style if it has an icon and text, then it should be more like a - // tab. So, cheat a little here. However, if it *is* only an icon - // the windows style works great, so just use that implementation. - bool hasMenu = btn.features & QStyleOptionButton::HasMenu; - bool hasIcon = !btn.icon.isNull(); - bool hasText = !btn.text.isEmpty(); - - if (!hasMenu) { - if (tds == kThemeStatePressed - || (tds == kThemeStateActive - && ((btn.features & QStyleOptionButton::DefaultButton && !d->autoDefaultButton) - || d->autoDefaultButton == btn.styleObject))) - btn.palette.setColor(QPalette::ButtonText, Qt::white); - } - - if (!hasIcon && !hasMenu) { - // ### this is really overly difficult, simplify. - // It basically tries to get the right font for "small" and "mini" icons. - QFont oldFont = p->font(); - QFont newFont = qt_app_fonts_hash()->value("QPushButton", QFont()); - ThemeFontID themeId = kThemePushButtonFont; - if (oldFont == newFont) { // Yes, use HITheme to draw the text for small sizes. - switch (d->aquaSizeConstrain(opt, w)) { - default: - break; - case QAquaSizeSmall: - themeId = kThemeSmallSystemFont; - break; - case QAquaSizeMini: - themeId = kThemeMiniSystemFont; - break; - } - } - - if (themeId == kThemePushButtonFont) { - QCommonStyle::drawControl(ce, &btn, p, w); - } else { - p->save(); - CGContextSetShouldAntialias(cg, true); - CGContextSetShouldSmoothFonts(cg, true); - HIThemeTextInfo tti; - tti.version = qt_mac_hitheme_version; - tti.state = tds; - QColor textColor; - textColor = btn.palette.buttonText().color(); - CGFloat colorComp[] = { static_cast(textColor.redF()), static_cast(textColor.greenF()), - static_cast(textColor.blueF()), static_cast(textColor.alphaF()) }; - CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace()); - CGContextSetFillColor(cg, colorComp); - tti.fontID = themeId; - tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter; - tti.verticalFlushness = kHIThemeTextVerticalFlushCenter; - tti.options = kHIThemeTextBoxOptionNone; - tti.truncationPosition = kHIThemeTextTruncationNone; - tti.truncationMaxLines = 1 + btn.text.count(QLatin1Char('\n')); - QCFString buttonText = qt_mac_removeMnemonics(btn.text); - QRect r = btn.rect; - HIRect bounds = qt_hirectForQRect(r); - HIThemeDrawTextBox(buttonText, &bounds, &tti, - cg, kHIThemeOrientationNormal); - p->restore(); - } - } else { - if (hasIcon && !hasText) { - QCommonStyle::drawControl(ce, &btn, p, w); - } else { - QRect freeContentRect = btn.rect; - QRect textRect = itemTextRect( - btn.fontMetrics, freeContentRect, Qt::AlignCenter, btn.state & State_Enabled, btn.text); - if (hasMenu) { - textRect.moveTo(w ? 15 : 11, textRect.top()); // Supports Qt Quick Controls - } - // Draw the icon: - if (hasIcon) { - int contentW = textRect.width(); - if (hasMenu) - contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4; - QIcon::Mode mode = btn.state & State_Enabled ? QIcon::Normal : QIcon::Disabled; - if (mode == QIcon::Normal && btn.state & State_HasFocus) - mode = QIcon::Active; - // Decide if the icon is should be on or off: - QIcon::State state = QIcon::Off; - if (btn.state & State_On) - state = QIcon::On; - QPixmap pixmap = btn.icon.pixmap(window, btn.iconSize, mode, state); - int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio(); - int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio(); - contentW += pixmapWidth + QMacStylePrivate::PushButtonContentPadding; - int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2; - int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2; - QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight); - QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect); - proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap); - int newOffset = iconDestRect.x() + iconDestRect.width() - + QMacStylePrivate::PushButtonContentPadding - textRect.x(); - textRect.adjust(newOffset, 0, newOffset, 0); - } - // Draw the text: - if (hasText) { - textRect = visualRect(btn.direction, freeContentRect, textRect); - proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette, - (btn.state & State_Enabled), btn.text, QPalette::ButtonText); - } - } - } - } - break; - case CE_ComboBoxLabel: - if (const QStyleOptionComboBox *cb = qstyleoption_cast(opt)) { - QStyleOptionComboBox comboCopy = *cb; - comboCopy.direction = Qt::LeftToRight; - QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w); - } - break; -#if QT_CONFIG(tabbar) - case CE_TabBarTabShape: - if (const QStyleOptionTab *tabOpt = qstyleoption_cast(opt)) { - if (tabOpt->documentMode) { - p->save(); - bool isUnified = false; - if (w) { - QRect tabRect = tabOpt->rect; - QPoint windowTabStart = w->mapTo(w->window(), tabRect.topLeft()); - isUnified = isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowTabStart.y()); - } - - const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt, w); - drawTabShape(p, tabOpt, isUnified, tabOverlap); - - p->restore(); - return; - } - - HIThemeTabDrawInfo tdi; - tdi.version = 1; - tdi.style = kThemeTabNonFront; - tdi.direction = getTabDirection(tabOpt->shape); - switch (d->aquaSizeConstrain(opt, w)) { - default: - case QAquaSizeUnknown: - case QAquaSizeLarge: - tdi.size = kHIThemeTabSizeNormal; - break; - case QAquaSizeSmall: - tdi.size = kHIThemeTabSizeSmall; - break; - case QAquaSizeMini: - tdi.size = kHIThemeTabSizeMini; - break; - } - bool verticalTabs = tdi.direction == kThemeTabWest || tdi.direction == kThemeTabEast; - QRect tabRect = tabOpt->rect; - - bool selected = tabOpt->state & State_Selected; - if (selected) { - if (!(tabOpt->state & State_Active)) - tdi.style = kThemeTabFrontUnavailable; - else if (!(tabOpt->state & State_Enabled)) - tdi.style = kThemeTabFrontInactive; - else - tdi.style = kThemeTabFront; - } else if (!(tabOpt->state & State_Active)) { - tdi.style = kThemeTabNonFrontUnavailable; - } else if (!(tabOpt->state & State_Enabled)) { - tdi.style = kThemeTabNonFrontInactive; - } else if (tabOpt->state & State_Sunken) { - tdi.style = kThemeTabNonFrontPressed; - } - if (tabOpt->state & State_HasFocus) - tdi.adornment = kHIThemeTabAdornmentFocus; - else - tdi.adornment = kHIThemeTabAdornmentNone; - tdi.kind = kHIThemeTabKindNormal; - - QStyleOptionTab::TabPosition tp = tabOpt->position; - QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition; - if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) { - if (sp == QStyleOptionTab::NextIsSelected) - sp = QStyleOptionTab::PreviousIsSelected; - else if (sp == QStyleOptionTab::PreviousIsSelected) - sp = QStyleOptionTab::NextIsSelected; - switch (tp) { - case QStyleOptionTab::Beginning: - tp = QStyleOptionTab::End; - break; - case QStyleOptionTab::End: - tp = QStyleOptionTab::Beginning; - break; - default: - break; - } - } - bool stretchTabs = (!verticalTabs && tabRect.height() > 22) || (verticalTabs && tabRect.width() > 22); - - switch (tp) { - case QStyleOptionTab::Beginning: - tdi.position = kHIThemeTabPositionFirst; - if (sp != QStyleOptionTab::NextIsSelected || stretchTabs) - tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator; - break; - case QStyleOptionTab::Middle: - tdi.position = kHIThemeTabPositionMiddle; - if (selected) - tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator; - if (sp != QStyleOptionTab::NextIsSelected || stretchTabs) // Also when we're selected. - tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator; - break; - case QStyleOptionTab::End: - tdi.position = kHIThemeTabPositionLast; - if (selected) - tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator; - break; - case QStyleOptionTab::OnlyOneTab: - tdi.position = kHIThemeTabPositionOnly; - break; - } - // HITheme doesn't stretch its tabs. Therefore we have to cheat and do the job ourselves. - if (stretchTabs) { - HIRect hirect = CGRectMake(0, 0, 23, 23); - QPixmap pm(23, 23); - pm.fill(Qt::transparent); - { - QMacCGContext pmcg(&pm); - HIThemeDrawTab(&hirect, &tdi, pmcg, kHIThemeOrientationNormal, 0); - } - QStyleHelper::drawBorderPixmap(pm, p, tabRect, 7, 7, 7, 7); - } else { - HIRect hirect = qt_hirectForQRect(tabRect); - HIThemeDrawTab(&hirect, &tdi, cg, kHIThemeOrientationNormal, 0); - } - } - break; - case CE_TabBarTabLabel: - if (const QStyleOptionTab *tab = qstyleoption_cast(opt)) { - QStyleOptionTab myTab = *tab; - ThemeTabDirection ttd = getTabDirection(myTab.shape); - bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast; - - // Check to see if we use have the same as the system font - // (QComboMenuItem is internal and should never be seen by the - // outside world, unless they read the source, in which case, it's - // their own fault). - bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem"); - - if (!myTab.documentMode && (myTab.state & State_Selected) && (myTab.state & State_Active)) - if (const auto *tabBar = qobject_cast(w)) - if (!tabBar->tabTextColor(tabBar->currentIndex()).isValid()) - myTab.palette.setColor(QPalette::WindowText, Qt::white); - - if (verticalTabs || nonDefaultFont || !tab->icon.isNull() - || !myTab.leftButtonSize.isEmpty() || !myTab.rightButtonSize.isEmpty()) { - int heightOffset = 0; - if (verticalTabs) { - heightOffset = -1; - } else if (nonDefaultFont) { - if (p->fontMetrics().height() == myTab.rect.height()) - heightOffset = 2; - } - myTab.rect.setHeight(myTab.rect.height() + heightOffset); - - QCommonStyle::drawControl(ce, &myTab, p, w); - } else { - p->save(); - CGContextSetShouldAntialias(cg, true); - CGContextSetShouldSmoothFonts(cg, true); - HIThemeTextInfo tti; - tti.version = qt_mac_hitheme_version; - tti.state = tds; - QColor textColor = myTab.palette.windowText().color(); - CGFloat colorComp[] = { static_cast(textColor.redF()), static_cast(textColor.greenF()), - static_cast(textColor.blueF()), static_cast(textColor.alphaF()) }; - CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace()); - CGContextSetFillColor(cg, colorComp); - switch (d->aquaSizeConstrain(opt, w)) { - default: - case QAquaSizeUnknown: - case QAquaSizeLarge: - tti.fontID = kThemeSystemFont; - break; - case QAquaSizeSmall: - tti.fontID = kThemeSmallSystemFont; - break; - case QAquaSizeMini: - tti.fontID = kThemeMiniSystemFont; - break; - } - tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter; - tti.verticalFlushness = kHIThemeTextVerticalFlushCenter; - tti.options = verticalTabs ? kHIThemeTextBoxOptionStronglyVertical : kHIThemeTextBoxOptionNone; - tti.truncationPosition = kHIThemeTextTruncationNone; - tti.truncationMaxLines = 1 + myTab.text.count(QLatin1Char('\n')); - QCFString tabText = qt_mac_removeMnemonics(myTab.text); - QRect r = myTab.rect.adjusted(0, 0, 0, -1); - HIRect bounds = qt_hirectForQRect(r); - HIThemeDrawTextBox(tabText, &bounds, &tti, cg, kHIThemeOrientationNormal); - p->restore(); - } - } - break; -#endif -#if QT_CONFIG(dockwidget) - case CE_DockWidgetTitle: - if (const QDockWidget *dockWidget = qobject_cast(w)) { - bool floating = dockWidget->isFloating(); - if (floating) { - ThemeDrawState tds = d->getDrawState(opt->state); - HIThemeWindowDrawInfo wdi; - wdi.version = qt_mac_hitheme_version; - wdi.state = tds; - wdi.windowType = kThemeMovableDialogWindow; - wdi.titleHeight = opt->rect.height(); - wdi.titleWidth = opt->rect.width(); - wdi.attributes = 0; - - HIRect titleBarRect; - HIRect tmpRect = qt_hirectForQRect(opt->rect); - { - QCFType titleRegion; - QRect newr = opt->rect.adjusted(0, 0, 2, 0); - HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion); - ptrHIShapeGetBounds(titleRegion, &tmpRect); - newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y)); - titleBarRect = qt_hirectForQRect(newr); - } - QMacCGContext cg(p); - HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0); - } else { - // fill title bar background - QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom()); - linearGrad.setColorAt(0, mainWindowGradientBegin); - linearGrad.setColorAt(1, mainWindowGradientEnd); - p->fillRect(opt->rect, linearGrad); - - // draw horizontal lines at top and bottom - p->save(); - p->setPen(mainWindowGradientBegin.lighter(114)); - p->drawLine(opt->rect.topLeft(), opt->rect.topRight()); - p->setPen(mainWindowGradientEnd.darker(114)); - p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight()); - p->restore(); - } - } - - // Draw the text... - if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast(opt)) { - if (!dwOpt->title.isEmpty()) { - - const bool verticalTitleBar = dwOpt->verticalTitleBar; - - QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, opt, w); - if (verticalTitleBar) { - QRect rect = dwOpt->rect; - QRect r = rect.transposed(); - - titleRect = QRect(r.left() + rect.bottom() - - titleRect.bottom(), - r.top() + titleRect.left() - rect.left(), - titleRect.height(), titleRect.width()); - - p->translate(r.left(), r.top() + r.width()); - p->rotate(-90); - p->translate(-r.left(), -r.top()); - } - - QFont oldFont = p->font(); - p->setFont(qt_app_fonts_hash()->value("QToolButton", p->font())); - QString text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, - titleRect.width()); - drawItemText(p, titleRect, - Qt::AlignCenter | Qt::TextShowMnemonic, dwOpt->palette, - dwOpt->state & State_Enabled, text, - QPalette::WindowText); - p->setFont(oldFont); - } - } - break; -#endif - case CE_FocusFrame: { - const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt, w); - const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt, w); - d->drawFocusRing(p, opt->rect, hMargin, vMargin); - break; } - case CE_MenuItem: - case CE_MenuEmptyArea: - if (const QStyleOptionMenuItem *mi = qstyleoption_cast(opt)) { - p->fillRect(mi->rect, opt->palette.background()); - QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, w); - int tabwidth = mi->tabWidth; - int maxpmw = mi->maxIconWidth; - bool active = mi->state & State_Selected; - bool enabled = mi->state & State_Enabled; - HIRect menuRect = qt_hirectForQRect(mi->menuRect); - HIRect itemRect = qt_hirectForQRect(mi->rect); - HIThemeMenuItemDrawInfo mdi; - mdi.version = qt_mac_hitheme_version; - mdi.itemType = kThemeMenuItemPlain; - if (!mi->icon.isNull()) - mdi.itemType |= kThemeMenuItemHasIcon; - if (mi->menuItemType == QStyleOptionMenuItem::SubMenu) - mdi.itemType |= kThemeMenuItemHierarchical | kThemeMenuItemHierBackground; - else - mdi.itemType |= kThemeMenuItemPopUpBackground; - if (enabled) - mdi.state = kThemeMenuActive; - else - mdi.state = kThemeMenuDisabled; - if (active) - mdi.state |= kThemeMenuSelected; - QRect contentRect; - if (mi->menuItemType == QStyleOptionMenuItem::Separator) { - // First arg should be &menurect, but wacky stuff happens then. - HIThemeDrawMenuSeparator(&itemRect, &itemRect, &mdi, - cg, kHIThemeOrientationNormal); - break; - } else { - HIRect cr; - bool needAlpha = mi->palette.color(QPalette::Button) == Qt::transparent; - if (needAlpha) { - CGContextSaveGState(cg); - CGContextSetAlpha(cg, 0.0); - } - HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi, - cg, kHIThemeOrientationNormal, &cr); - if (needAlpha) - CGContextRestoreGState(cg); - if (ce == CE_MenuEmptyArea) - break; - contentRect = qt_qrectForHIRect(cr); - } - int xpos = contentRect.x() + 18; - int checkcol = maxpmw; - if (!enabled) - p->setPen(mi->palette.text().color()); - else if (active) - p->setPen(mi->palette.highlightedText().color()); - else - p->setPen(mi->palette.buttonText().color()); - - if (mi->checked) { - QStyleOption checkmarkOpt; - checkmarkOpt.initFrom(w); - - const int mw = checkcol + macItemFrame; - const int mh = contentRect.height() + macItemFrame; - const int xp = contentRect.x() + macItemFrame; - checkmarkOpt.rect = QRect(xp, contentRect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh); - - checkmarkOpt.state.setFlag(State_On, active); - checkmarkOpt.state.setFlag(State_Enabled, enabled); - if (widgetSize == QAquaSizeMini) - checkmarkOpt.state |= State_Mini; - else if (widgetSize == QAquaSizeSmall) - checkmarkOpt.state |= State_Small; - - // We let drawPrimitive(PE_IndicatorMenuCheckMark) pick the right color - checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color()); - checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color()); - - proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p, w); - } - if (!mi->icon.isNull()) { - QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal - : QIcon::Disabled; - // Always be normal or disabled to follow the Mac style. - int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize); - QSize iconSize(smallIconSize, smallIconSize); -#if QT_CONFIG(combobox) - if (const QComboBox *comboBox = qobject_cast(w)) { - iconSize = comboBox->iconSize(); - } -#endif - QPixmap pixmap = mi->icon.pixmap(window, iconSize, mode); - int pixw = pixmap.width() / pixmap.devicePixelRatio(); - int pixh = pixmap.height() / pixmap.devicePixelRatio(); - QRect cr(xpos, contentRect.y(), checkcol, contentRect.height()); - QRect pmr(0, 0, pixw, pixh); - pmr.moveCenter(cr.center()); - p->drawPixmap(pmr.topLeft(), pixmap); - xpos += pixw + 6; - } - - QString s = mi->text; - if (!s.isEmpty()) { - int t = s.indexOf(QLatin1Char('\t')); - int text_flags = Qt::AlignRight | Qt::AlignVCenter | Qt::TextHideMnemonic - | Qt::TextSingleLine | Qt::AlignAbsolute; - int yPos = contentRect.y(); - if (widgetSize == QAquaSizeMini) - yPos += 1; - p->save(); - if (t >= 0) { - p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font())); - int xp = contentRect.right() - tabwidth - macRightBorder - - macItemHMargin - macItemFrame + 1; - p->drawText(xp, yPos, tabwidth, contentRect.height(), text_flags, - s.mid(t + 1)); - s = s.left(t); - } - - const int xm = macItemFrame + maxpmw + macItemHMargin; - QFont myFont = mi->font; - // myFont may not have any "hard" flags set. We override - // the point size so that when it is resolved against the device, this font will win. - // This is mainly to handle cases where someone sets the font on the window - // and then the combo inherits it and passes it onward. At that point the resolve mask - // is very, very weak. This makes it stonger. - myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF()); - p->setFont(myFont); - p->drawText(xpos, yPos, contentRect.width() - xm - tabwidth + 1, - contentRect.height(), text_flags ^ Qt::AlignRight, s); - p->restore(); - } - } - break; - case CE_MenuHMargin: - case CE_MenuVMargin: - case CE_MenuTearoff: - case CE_MenuScroller: - if (const QStyleOptionMenuItem *mi = qstyleoption_cast(opt)) { - p->fillRect(mi->rect, opt->palette.background()); - - HIRect menuRect = qt_hirectForQRect(mi->menuRect); - HIRect itemRect = qt_hirectForQRect(mi->rect); - HIThemeMenuItemDrawInfo mdi; - mdi.version = qt_mac_hitheme_version; - if (!(opt->state & State_Enabled)) - mdi.state = kThemeMenuDisabled; - else if (opt->state & State_Selected) - mdi.state = kThemeMenuSelected; - else - mdi.state = kThemeMenuActive; - if (ce == CE_MenuScroller) { - if (opt->state & State_DownArrow) - mdi.itemType = kThemeMenuItemScrollDownArrow; - else - mdi.itemType = kThemeMenuItemScrollUpArrow; - } else { - mdi.itemType = kThemeMenuItemPlain; - } - HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi, - cg, - kHIThemeOrientationNormal, 0); - if (ce == CE_MenuTearoff) { - p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine)); - p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1, - mi->rect.x() + mi->rect.width() - 4, - mi->rect.y() + mi->rect.height() / 2 - 1); - p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine)); - p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2, - mi->rect.x() + mi->rect.width() - 4, - mi->rect.y() + mi->rect.height() / 2); - } - } - break; - case CE_MenuBarItem: - if (const QStyleOptionMenuItem *mi = qstyleoption_cast(opt)) { - HIRect menuRect = qt_hirectForQRect(mi->menuRect); - HIRect itemRect = qt_hirectForQRect(mi->rect); - - const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken); - if (selected) { - // Draw a selected menu item background: - HIThemeMenuItemDrawInfo mdi; - mdi.version = qt_mac_hitheme_version; - mdi.state = kThemeMenuSelected; - mdi.itemType = kThemeMenuItemPlain; - HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi, cg, kHIThemeOrientationNormal, 0); - } else { - // Draw the toolbar background: - HIThemeMenuBarDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - bdi.state = kThemeMenuBarNormal; - bdi.attributes = 0; - HIThemeDrawMenuBarBackground(&menuRect, &bdi, cg, kHIThemeOrientationNormal); - } - - if (!mi->icon.isNull()) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); - drawItemPixmap(p, mi->rect, - Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip - | Qt::TextSingleLine, - mi->icon.pixmap(window, QSize(iconExtent, iconExtent), - (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled)); - } else { - drawItemText(p, mi->rect, - Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip - | Qt::TextSingleLine, - mi->palette, mi->state & State_Enabled, - mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText); - } - } - break; - case CE_MenuBarEmptyArea: - if (const QStyleOptionMenuItem *mi = qstyleoption_cast(opt)) { - HIThemeMenuBarDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - bdi.state = kThemeMenuBarNormal; - bdi.attributes = 0; - HIRect hirect = qt_hirectForQRect(mi->rect); - HIThemeDrawMenuBarBackground(&hirect, &bdi, cg, - kHIThemeOrientationNormal); - break; - } - case CE_ProgressBarContents: - if (const QStyleOptionProgressBar *pb = qstyleoption_cast(opt)) { - HIThemeTrackDrawInfo tdi; - tdi.version = qt_mac_hitheme_version; - tdi.reserved = 0; - bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0); - const bool vertical = pb->orientation == Qt::Vertical; - const bool inverted = pb->invertedAppearance; - bool reverse = (!vertical && (pb->direction == Qt::RightToLeft)); - if (inverted) - reverse = !reverse; - switch (d->aquaSizeConstrain(opt, w)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - tdi.kind = !isIndeterminate ? kThemeLargeProgressBar - : kThemeLargeIndeterminateBar; - break; - case QAquaSizeMini: - case QAquaSizeSmall: - tdi.kind = !isIndeterminate ? kThemeProgressBar : kThemeIndeterminateBar; - break; - } - tdi.bounds = qt_hirectForQRect(pb->rect); - tdi.max = pb->maximum; - tdi.min = pb->minimum; - tdi.value = pb->progress; - tdi.attributes = vertical ? 0 : kThemeTrackHorizontal; - - if (isIndeterminate) { - if (QProgressStyleAnimation *animation = qobject_cast(d->animation(opt->styleObject))) - tdi.trackInfo.progress.phase = animation->animationStep(); - else if (opt->styleObject) - d->startAnimation(new QProgressStyleAnimation(d->animateSpeed(QMacStylePrivate::AquaProgressBar), opt->styleObject)); - } else { - d->stopAnimation(opt->styleObject); - } - if (!(pb->state & State_Active)) - tdi.enableState = kThemeTrackInactive; - else if (!(pb->state & State_Enabled)) - tdi.enableState = kThemeTrackDisabled; - else - tdi.enableState = kThemeTrackActive; - HIThemeOrientation drawOrientation = kHIThemeOrientationNormal; - if (reverse) { - if (vertical) { - drawOrientation = kHIThemeOrientationInverted; - } else { - CGContextSaveGState(cg); - CGContextTranslateCTM(cg, pb->rect.width(), 0); - CGContextScaleCTM(cg, -1, 1); - } - } - HIThemeDrawTrack(&tdi, 0, cg, drawOrientation); - if (reverse && !vertical) - CGContextRestoreGState(cg); - } - break; - case CE_ProgressBarLabel: - case CE_ProgressBarGroove: - break; - case CE_SizeGrip: { - if (w && w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) { - HIThemeGrowBoxDrawInfo gdi; - gdi.version = qt_mac_hitheme_version; - gdi.state = tds; - gdi.kind = kHIThemeGrowBoxKindNormal; - gdi.direction = kThemeGrowRight | kThemeGrowDown; - gdi.size = kHIThemeGrowBoxSizeNormal; - HIPoint pt = CGPointMake(opt->rect.x(), opt->rect.y()); - HIThemeDrawGrowBox(&pt, &gdi, cg, kHIThemeOrientationNormal); - } else { - // It isn't possible to draw a transparent size grip with the - // native API, so we do it ourselves here. - const bool metal = qt_mac_is_metal(w); - QPen lineColor = metal ? QColor(236, 236, 236) : QColor(82, 82, 82, 192); - QPen metalHighlight = QColor(5, 5, 5, 192); - lineColor.setWidth(1); - p->save(); - p->setRenderHint(QPainter::Antialiasing); - p->setPen(lineColor); - const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection(); - const int NumLines = metal ? 4 : 3; - for (int l = 0; l < NumLines; ++l) { - const int offset = (l * 4 + (metal ? 2 : 3)); - QPoint start, end; - if (layoutDirection == Qt::LeftToRight) { - start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1); - end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset); - } else { - start = QPoint(offset, opt->rect.height() - 1); - end = QPoint(1, opt->rect.height() - offset); - } - p->drawLine(start, end); - if (metal) { - p->setPen(metalHighlight); - p->setRenderHint(QPainter::Antialiasing, false); - p->drawLine(start + QPoint(0, -1), end + QPoint(0, -1)); - p->setRenderHint(QPainter::Antialiasing, true); - p->setPen(lineColor); - } - } - p->restore(); - } - break; - } - case CE_Splitter: - if (opt->rect.width() > 1 && opt->rect.height() > 1){ - HIThemeSplitterDrawInfo sdi; - sdi.version = qt_mac_hitheme_version; - sdi.state = tds; - sdi.adornment = kHIThemeSplitterAdornmentMetal; - HIRect hirect = qt_hirectForQRect(opt->rect); - HIThemeDrawPaneSplitter(&hirect, &sdi, cg, kHIThemeOrientationNormal); - } else { - QPen oldPen = p->pen(); - p->setPen(opt->palette.dark().color()); - if (opt->state & QStyle::State_Horizontal) - p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft()); - else - p->drawLine(opt->rect.topLeft(), opt->rect.topRight()); - p->setPen(oldPen); - } - break; - case CE_RubberBand: - if (const QStyleOptionRubberBand *rubber = qstyleoption_cast(opt)) { - QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight)); - if (!rubber->opaque) { - QColor strokeColor; - // I retrieved these colors from the Carbon-Dev mailing list - strokeColor.setHsvF(0, 0, 0.86, 1.0); - fillColor.setHsvF(0, 0, 0.53, 0.25); - if (opt->rect.width() * opt->rect.height() <= 3) { - p->fillRect(opt->rect, strokeColor); - } else { - QPen oldPen = p->pen(); - QBrush oldBrush = p->brush(); - QPen pen(strokeColor); - p->setPen(pen); - p->setBrush(fillColor); - QRect adjusted = opt->rect.adjusted(1, 1, -1, -1); - if (adjusted.isValid()) - p->drawRect(adjusted); - p->setPen(oldPen); - p->setBrush(oldBrush); - } - } else { - p->fillRect(opt->rect, fillColor); - } - } - break; -#ifndef QT_NO_TOOLBAR - case CE_ToolBar: { - const QStyleOptionToolBar *toolBar = qstyleoption_cast(opt); - - // Unified title and toolbar drawing. In this mode the cocoa platform plugin will - // fill the top toolbar area part with a background gradient that "unifies" with - // the title bar. The following code fills the toolBar area with transparent pixels - // to make that gradient visible. - if (w) { -#if QT_CONFIG(mainwindow) - if (QMainWindow * mainWindow = qobject_cast(w->window())) { - if (toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && mainWindow->unifiedTitleAndToolBarOnMac()) { - - // fill with transparent pixels. - p->save(); - p->setCompositionMode(QPainter::CompositionMode_Source); - p->fillRect(opt->rect, Qt::transparent); - p->restore(); - - // Drow a horizontal sepearator line at the toolBar bottom if the "unified" area ends here. - // There might be additional toolbars or other widgets such as tab bars in document - // mode below. Determine this by making a unified toolbar area test for the row below - // this toolbar. - QPoint windowToolbarEnd = w->mapTo(w->window(), opt->rect.bottomLeft()); - bool isEndOfUnifiedArea = !isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowToolbarEnd.y() + 1); - if (isEndOfUnifiedArea) { - SInt32 margin; - GetThemeMetric(kThemeMetricSeparatorSize, &margin); - CGRect separatorRect = CGRectMake(opt->rect.left(), opt->rect.bottom(), opt->rect.width(), margin); - HIThemeSeparatorDrawInfo separatorDrawInfo; - separatorDrawInfo.version = 0; - separatorDrawInfo.state = qt_macWindowMainWindow(mainWindow) ? kThemeStateActive : kThemeStateInactive; - QMacCGContext cg(p); - HIThemeDrawSeparator(&separatorRect, &separatorDrawInfo, cg, kHIThemeOrientationNormal); - } - break; - } - } -#endif - } - - // draw background gradient - QLinearGradient linearGrad; - if (opt->state & State_Horizontal) - linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom()); - else - linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0); - - linearGrad.setColorAt(0, mainWindowGradientBegin); - linearGrad.setColorAt(1, mainWindowGradientEnd); - p->fillRect(opt->rect, linearGrad); - - p->save(); - if (opt->state & State_Horizontal) { - p->setPen(mainWindowGradientBegin.lighter(114)); - p->drawLine(opt->rect.topLeft(), opt->rect.topRight()); - p->setPen(mainWindowGradientEnd.darker(114)); - p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight()); - - } else { - p->setPen(mainWindowGradientBegin.lighter(114)); - p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft()); - p->setPen(mainWindowGradientEnd.darker(114)); - p->drawLine(opt->rect.topRight(), opt->rect.bottomRight()); - } - p->restore(); - - - } break; -#endif - default: - QCommonStyle::drawControl(ce, opt, p, w); - break; - } -} - -static void setLayoutItemMargins(int left, int top, int right, int bottom, QRect *rect, Qt::LayoutDirection dir) -{ - if (dir == Qt::RightToLeft) { - rect->adjust(-right, top, -left, bottom); - } else { - rect->adjust(left, top, right, bottom); - } -} - -QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, - const QWidget *widget) const -{ - Q_D(const QMacStyle); - QRect rect; - int controlSize = getControlSize(opt, widget); - - switch (sr) { - case SE_ItemViewItemText: - if (const QStyleOptionViewItem *vopt = qstyleoption_cast(opt)) { - int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget); - // We add the focusframeargin between icon and text in commonstyle - rect = QCommonStyle::subElementRect(sr, opt, widget); - if (vopt->features & QStyleOptionViewItem::HasDecoration) - rect.adjust(-fw, 0, 0, 0); - } - break; - case SE_ToolBoxTabContents: - rect = QCommonStyle::subElementRect(sr, opt, widget); - break; - case SE_PushButtonContents: - if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { - // Unlike Carbon, we want the button to always be drawn inside its bounds. - // Therefore, the button is a bit smaller, so that even if it got focus, - // the focus 'shadow' will be inside. Adjust the content rect likewise. - HIThemeButtonDrawInfo bdi; - d->initHIThemePushButton(btn, widget, d->getDrawState(opt->state), &bdi); - HIRect contentRect = d->pushButtonContentBounds(btn, &bdi); - rect = qt_qrectForHIRect(contentRect); - } - break; - case SE_HeaderLabel: { - int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget); - rect.setRect(opt->rect.x() + margin, opt->rect.y(), - opt->rect.width() - margin * 2, opt->rect.height() - 2); - if (const QStyleOptionHeader *header = qstyleoption_cast(opt)) { - // Subtract width needed for arrow, if there is one - if (header->sortIndicator != QStyleOptionHeader::None) { - if (opt->state & State_Horizontal) - rect.setWidth(rect.width() - (opt->rect.height() / 2) - (margin * 2)); - else - rect.setHeight(rect.height() - (opt->rect.width() / 2) - (margin * 2)); - } - } - rect = visualRect(opt->direction, opt->rect, rect); - break; - } - case SE_ProgressBarGroove: - // Wrong in the secondary dimension, but accurate enough in the main dimension. - rect = opt->rect; - break; - case SE_ProgressBarLabel: - break; - case SE_ProgressBarContents: - rect = opt->rect; - break; - case SE_TreeViewDisclosureItem: { - HIRect inRect = CGRectMake(opt->rect.x(), opt->rect.y(), - opt->rect.width(), opt->rect.height()); - HIThemeButtonDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - bdi.state = kThemeStateActive; - bdi.kind = kThemeDisclosureButton; - bdi.value = kThemeDisclosureRight; - bdi.adornment = kThemeAdornmentNone; - HIRect contentRect; - HIThemeGetButtonContentBounds(&inRect, &bdi, &contentRect); - QCFType shape; - HIRect outRect; - HIThemeGetButtonShape(&inRect, &bdi, &shape); - ptrHIShapeGetBounds(shape, &outRect); - rect = QRect(int(outRect.origin.x + DisclosureOffset), int(outRect.origin.y), - int(contentRect.origin.x - outRect.origin.x + DisclosureOffset), - int(outRect.size.height)); - break; - } -#if QT_CONFIG(tabwidget) - case SE_TabWidgetLeftCorner: - if (const QStyleOptionTabWidgetFrame *twf - = qstyleoption_cast(opt)) { - switch (twf->shape) { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize); - break; - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()), - twf->leftCornerWidgetSize); - break; - default: - break; - } - rect = visualRect(twf->direction, twf->rect, rect); - } - break; - case SE_TabWidgetRightCorner: - if (const QStyleOptionTabWidgetFrame *twf - = qstyleoption_cast(opt)) { - switch (twf->shape) { - case QTabBar::RoundedNorth: - case QTabBar::TriangularNorth: - rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0), - twf->rightCornerWidgetSize); - break; - case QTabBar::RoundedSouth: - case QTabBar::TriangularSouth: - rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), - twf->rect.height() - twf->rightCornerWidgetSize.height()), - twf->rightCornerWidgetSize); - break; - default: - break; - } - rect = visualRect(twf->direction, twf->rect, rect); - } - break; - case SE_TabWidgetTabContents: - rect = QCommonStyle::subElementRect(sr, opt, widget); - if (const QStyleOptionTabWidgetFrame *twf - = qstyleoption_cast(opt)) { - if (twf->lineWidth != 0) { - switch (getTabDirection(twf->shape)) { - case kThemeTabNorth: - rect.adjust(+1, +14, -1, -1); - break; - case kThemeTabSouth: - rect.adjust(+1, +1, -1, -14); - break; - case kThemeTabWest: - rect.adjust(+14, +1, -1, -1); - break; - case kThemeTabEast: - rect.adjust(+1, +1, -14, -1); - } - } - } - break; - case SE_TabBarTabText: - if (const QStyleOptionTab *tab = qstyleoption_cast(opt)) { - QRect dummyIconRect; - d->tabLayout(tab, widget, &rect, &dummyIconRect); - } - break; - case SE_TabBarTabLeftButton: - case SE_TabBarTabRightButton: - if (const QStyleOptionTab *tab = qstyleoption_cast(opt)) { - bool selected = tab->state & State_Selected; - int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget); - int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget); - int hpadding = 5; - - bool verticalTabs = tab->shape == QTabBar::RoundedEast - || tab->shape == QTabBar::RoundedWest - || tab->shape == QTabBar::TriangularEast - || tab->shape == QTabBar::TriangularWest; - - QRect tr = tab->rect; - if (tab->shape == QTabBar::RoundedSouth || tab->shape == QTabBar::TriangularSouth) - verticalShift = -verticalShift; - if (verticalTabs) { - qSwap(horizontalShift, verticalShift); - horizontalShift *= -1; - verticalShift *= -1; - } - if (tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularWest) - horizontalShift = -horizontalShift; - - tr.adjust(0, 0, horizontalShift, verticalShift); - if (selected) - { - tr.setBottom(tr.bottom() - verticalShift); - tr.setRight(tr.right() - horizontalShift); - } - - QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize; - int w = size.width(); - int h = size.height(); - int midHeight = static_cast(qCeil(float(tr.height() - h) / 2)); - int midWidth = ((tr.width() - w) / 2); - - bool atTheTop = true; - switch (tab->shape) { - case QTabBar::RoundedWest: - case QTabBar::TriangularWest: - atTheTop = (sr == SE_TabBarTabLeftButton); - break; - case QTabBar::RoundedEast: - case QTabBar::TriangularEast: - atTheTop = (sr == SE_TabBarTabRightButton); - break; - default: - if (sr == SE_TabBarTabLeftButton) - rect = QRect(tab->rect.x() + hpadding, midHeight, w, h); - else - rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h); - rect = visualRect(tab->direction, tab->rect, rect); - } - if (verticalTabs) { - if (atTheTop) - rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h); - else - rect = QRect(midWidth, tr.y() + hpadding, w, h); - } - } - break; -#endif - case SE_LineEditContents: - rect = QCommonStyle::subElementRect(sr, opt, widget); -#if QT_CONFIG(combobox) - if (widget && qobject_cast(widget->parentWidget())) - rect.adjust(-1, -2, 0, 0); - else -#endif - rect.adjust(-1, -1, 0, +1); - break; - case SE_CheckBoxLayoutItem: - rect = opt->rect; - if (controlSize == QAquaSizeLarge) { - setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction); - } else if (controlSize == QAquaSizeSmall) { - setLayoutItemMargins(+1, +5, 0 /* fix */, -6, &rect, opt->direction); - } else { - setLayoutItemMargins(0, +7, 0 /* fix */, -6, &rect, opt->direction); - } - break; - case SE_ComboBoxLayoutItem: -#ifndef QT_NO_TOOLBAR - if (widget && qobject_cast(widget->parentWidget())) { - // Do nothing, because QToolbar needs the entire widget rect. - // Otherwise it will be clipped. Equivalent to - // widget->setAttribute(Qt::WA_LayoutUsesWidgetRect), but without - // all the hassle. - } else -#endif - { - rect = opt->rect; - if (controlSize == QAquaSizeLarge) { - rect.adjust(+3, +2, -3, -4); - } else if (controlSize == QAquaSizeSmall) { - setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction); - } else { - setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction); - } - } - break; - case SE_LabelLayoutItem: - rect = opt->rect; - setLayoutItemMargins(+1, 0 /* SHOULD be -1, done for alignment */, 0, 0 /* SHOULD be -1, done for alignment */, &rect, opt->direction); - break; - case SE_ProgressBarLayoutItem: { - rect = opt->rect; - int bottom = SIZE(3, 8, 8); - if (opt->state & State_Horizontal) { - rect.adjust(0, +1, 0, -bottom); - } else { - setLayoutItemMargins(+1, 0, -bottom, 0, &rect, opt->direction); - } - break; - } - case SE_PushButtonLayoutItem: - if (const QStyleOptionButton *buttonOpt - = qstyleoption_cast(opt)) { - if ((buttonOpt->features & QStyleOptionButton::Flat)) - break; // leave rect alone - } - rect = opt->rect; - if (controlSize == QAquaSizeLarge) { - rect.adjust(+6, +4, -6, -8); - } else if (controlSize == QAquaSizeSmall) { - rect.adjust(+5, +4, -5, -6); - } else { - rect.adjust(+1, 0, -1, -2); - } - break; - case SE_RadioButtonLayoutItem: - rect = opt->rect; - if (controlSize == QAquaSizeLarge) { - setLayoutItemMargins(+2, +2 /* SHOULD BE +3, done for alignment */, - 0, -4 /* SHOULD BE -3, done for alignment */, &rect, opt->direction); - } else if (controlSize == QAquaSizeSmall) { - rect.adjust(0, +6, 0 /* fix */, -5); - } else { - rect.adjust(0, +6, 0 /* fix */, -7); - } - break; - case SE_SliderLayoutItem: - if (const QStyleOptionSlider *sliderOpt - = qstyleoption_cast(opt)) { - rect = opt->rect; - if (sliderOpt->tickPosition == QSlider::NoTicks) { - int above = SIZE(3, 0, 2); - int below = SIZE(4, 3, 0); - if (sliderOpt->orientation == Qt::Horizontal) { - rect.adjust(0, +above, 0, -below); - } else { - rect.adjust(+above, 0, -below, 0); //### Seems that QSlider flip the position of the ticks in reverse mode. - } - } else if (sliderOpt->tickPosition == QSlider::TicksAbove) { - int below = SIZE(3, 2, 0); - if (sliderOpt->orientation == Qt::Horizontal) { - rect.setHeight(rect.height() - below); - } else { - rect.setWidth(rect.width() - below); - } - } else if (sliderOpt->tickPosition == QSlider::TicksBelow) { - int above = SIZE(3, 2, 0); - if (sliderOpt->orientation == Qt::Horizontal) { - rect.setTop(rect.top() + above); - } else { - rect.setLeft(rect.left() + above); - } - } - } - break; - case SE_FrameLayoutItem: - // hack because QStyleOptionFrame doesn't have a frameStyle member - if (const QFrame *frame = qobject_cast(widget)) { - rect = opt->rect; - switch (frame->frameStyle() & QFrame::Shape_Mask) { - case QFrame::HLine: - rect.adjust(0, +1, 0, -1); - break; - case QFrame::VLine: - rect.adjust(+1, 0, -1, 0); - break; - default: - ; - } - } - break; - case SE_GroupBoxLayoutItem: - rect = opt->rect; - if (const QStyleOptionGroupBox *groupBoxOpt = - qstyleoption_cast(opt)) { - /* - AHIG is very inconsistent when it comes to group boxes. - Basically, we make sure that (non-checkable) group boxes - and tab widgets look good when laid out side by side. - */ - if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox - | QStyle::SC_GroupBoxLabel)) { - int delta; - if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) { - delta = SIZE(8, 4, 4); // guess - } else { - delta = SIZE(15, 12, 12); // guess - } - rect.setTop(rect.top() + delta); - } - } - rect.setBottom(rect.bottom() - 1); - break; -#if QT_CONFIG(tabwidget) - case SE_TabWidgetLayoutItem: - if (const QStyleOptionTabWidgetFrame *tabWidgetOpt = - qstyleoption_cast(opt)) { - /* - AHIG specifies "12 or 14" as the distance from the window - edge. We choose 14 and since the default top margin is 20, - the overlap is 6. - */ - rect = tabWidgetOpt->rect; - if (tabWidgetOpt->shape == QTabBar::RoundedNorth) - rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */)); - } - break; -#endif -#if QT_CONFIG(dockwidget) - case SE_DockWidgetCloseButton: - case SE_DockWidgetFloatButton: - case SE_DockWidgetTitleBarText: - case SE_DockWidgetIcon: { - int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt, widget); - int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt, widget); - QRect srect = opt->rect; - - const QStyleOptionDockWidget *dwOpt - = qstyleoption_cast(opt); - bool canClose = dwOpt == 0 ? true : dwOpt->closable; - bool canFloat = dwOpt == 0 ? false : dwOpt->floatable; - - const bool verticalTitleBar = dwOpt->verticalTitleBar; - - // If this is a vertical titlebar, we transpose and work as if it was - // horizontal, then transpose again. - if (verticalTitleBar) - srect = srect.transposed(); - - do { - int right = srect.right(); - int left = srect.left(); - - QRect closeRect; - if (canClose) { - QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton, - opt, widget).actualSize(QSize(iconSize, iconSize)); - sz += QSize(buttonMargin, buttonMargin); - if (verticalTitleBar) - sz = sz.transposed(); - closeRect = QRect(left, - srect.center().y() - sz.height()/2, - sz.width(), sz.height()); - left = closeRect.right() + 1; - } - if (sr == SE_DockWidgetCloseButton) { - rect = closeRect; - break; - } - - QRect floatRect; - if (canFloat) { - QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton, - opt, widget).actualSize(QSize(iconSize, iconSize)); - sz += QSize(buttonMargin, buttonMargin); - if (verticalTitleBar) - sz = sz.transposed(); - floatRect = QRect(left, - srect.center().y() - sz.height()/2, - sz.width(), sz.height()); - left = floatRect.right() + 1; - } - if (sr == SE_DockWidgetFloatButton) { - rect = floatRect; - break; - } - - QRect iconRect; - if (const QDockWidget *dw = qobject_cast(widget)) { - QIcon icon; - if (dw->isFloating()) - icon = dw->windowIcon(); - if (!icon.isNull() - && icon.cacheKey() != QApplication::windowIcon().cacheKey()) { - QSize sz = icon.actualSize(QSize(rect.height(), rect.height())); - if (verticalTitleBar) - sz = sz.transposed(); - iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2, - sz.width(), sz.height()); - right = iconRect.left() - 1; - } - } - if (sr == SE_DockWidgetIcon) { - rect = iconRect; - break; - } - - QRect textRect = QRect(left, srect.top(), - right - left, srect.height()); - if (sr == SE_DockWidgetTitleBarText) { - rect = textRect; - break; - } - } while (false); - - if (verticalTitleBar) { - rect = QRect(srect.left() + rect.top() - srect.top(), - srect.top() + srect.right() - rect.right(), - rect.height(), rect.width()); - } else { - rect = visualRect(opt->direction, srect, rect); - } - break; - } -#endif - default: - rect = QCommonStyle::subElementRect(sr, opt, widget); - break; - } - return rect; -} - -static inline void drawToolbarButtonArrow(const QRect &toolButtonRect, ThemeDrawState tds, CGContextRef cg) -{ - QRect arrowRect = QRect(toolButtonRect.right() - 9, toolButtonRect.bottom() - 9, 7, 5); - HIThemePopupArrowDrawInfo padi; - padi.version = qt_mac_hitheme_version; - padi.state = tds; - padi.orientation = kThemeArrowDown; - padi.size = kThemeArrow7pt; - HIRect hirect = qt_hirectForQRect(arrowRect); - HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal); -} - -void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, - const QWidget *widget) const -{ - Q_D(const QMacStyle); - ThemeDrawState tds = d->getDrawState(opt->state); - QMacCGContext cg(p); - QWindow *window = widget && widget->window() ? widget->window()->windowHandle() : - QStyleHelper::styleObjectWindow(opt->styleObject); - const_cast(d)->resolveCurrentNSView(window); - switch (cc) { - case CC_Slider: - case CC_ScrollBar: - if (const QStyleOptionSlider *slider = qstyleoption_cast(opt)) { - HIThemeTrackDrawInfo tdi; - d->getSliderInfo(cc, slider, &tdi, widget); - if (slider->state & State_Sunken) { - if (cc == CC_Slider) { - if (slider->activeSubControls == SC_SliderHandle) - tdi.trackInfo.slider.pressState = kThemeThumbPressed; - else if (slider->activeSubControls == SC_SliderGroove) - tdi.trackInfo.slider.pressState = kThemeLeftTrackPressed; - } else { - if (slider->activeSubControls == SC_ScrollBarSubLine - || slider->activeSubControls == SC_ScrollBarAddLine) { - // This test looks complex but it basically boils down - // to the following: The "RTL look" on the mac also - // changed the directions of the controls, that's not - // what people expect (an arrow is an arrow), so we - // kind of fake and say the opposite button is hit. - // This works great, up until 10.4 which broke the - // scroll bars, so I also have actually do something - // similar when I have an upside down scroll bar - // because on Tiger I only "fake" the reverse stuff. - bool reverseHorizontal = (slider->direction == Qt::RightToLeft - && slider->orientation == Qt::Horizontal); - - if ((reverseHorizontal - && slider->activeSubControls == SC_ScrollBarAddLine) - || (!reverseHorizontal - && slider->activeSubControls == SC_ScrollBarSubLine)) { - tdi.trackInfo.scrollbar.pressState = kThemeRightInsideArrowPressed - | kThemeLeftOutsideArrowPressed; - } else { - tdi.trackInfo.scrollbar.pressState = kThemeLeftInsideArrowPressed - | kThemeRightOutsideArrowPressed; - } - } else if (slider->activeSubControls == SC_ScrollBarAddPage) { - tdi.trackInfo.scrollbar.pressState = kThemeRightTrackPressed; - } else if (slider->activeSubControls == SC_ScrollBarSubPage) { - tdi.trackInfo.scrollbar.pressState = kThemeLeftTrackPressed; - } else if (slider->activeSubControls == SC_ScrollBarSlider) { - tdi.trackInfo.scrollbar.pressState = kThemeThumbPressed; - } - } - } - HIRect macRect; - bool tracking = slider->sliderPosition == slider->sliderValue; - if (!tracking) { - // Small optimization, the same as q->subControlRect - QCFType shape; - HIThemeGetTrackThumbShape(&tdi, &shape); - ptrHIShapeGetBounds(shape, &macRect); - tdi.value = slider->sliderValue; - } - - // Remove controls from the scroll bar if it is to short to draw them correctly. - // This is done in two stages: first the thumb indicator is removed when it is - // no longer possible to move it, second the up/down buttons are removed when - // there is not enough space for them. - if (cc == CC_ScrollBar) { - if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject)) - QMacStylePrivate::scrollBars.append(QPointer(opt->styleObject)); - const int scrollBarLength = (slider->orientation == Qt::Horizontal) - ? slider->rect.width() : slider->rect.height(); - const QMacStyle::WidgetSizePolicy sizePolicy = widgetSizePolicy(widget, opt); - if (scrollBarLength < scrollButtonsCutoffSize(thumbIndicatorCutoff, sizePolicy)) - tdi.attributes &= ~kThemeTrackShowThumb; - if (scrollBarLength < scrollButtonsCutoffSize(scrollButtonsCutoff, sizePolicy)) - tdi.enableState = kThemeTrackNothingToScroll; - } else { - if (!(slider->subControls & SC_SliderHandle)) - tdi.attributes &= ~kThemeTrackShowThumb; - if (!(slider->subControls & SC_SliderGroove)) - tdi.attributes |= kThemeTrackHideTrack; - } - - const bool isHorizontal = slider->orientation == Qt::Horizontal; - - if (cc == CC_ScrollBar && proxy()->styleHint(SH_ScrollBar_Transient, opt, widget)) { - bool wasActive = false; - CGFloat opacity = 0.0; - CGFloat expandScale = 1.0; - CGFloat expandOffset = -1.0; - bool shouldExpand = false; - const CGFloat maxExpandScale = tdi.kind == kThemeSmallScrollBar ? 11.0 / 7.0 : 13.0 / 9.0; - - if (QObject *styleObject = opt->styleObject) { - int oldPos = styleObject->property("_q_stylepos").toInt(); - int oldMin = styleObject->property("_q_stylemin").toInt(); - int oldMax = styleObject->property("_q_stylemax").toInt(); - QRect oldRect = styleObject->property("_q_stylerect").toRect(); - QStyle::State oldState = static_cast(styleObject->property("_q_stylestate").value()); - uint oldActiveControls = styleObject->property("_q_stylecontrols").toUInt(); - - // a scrollbar is transient when the scrollbar itself and - // its sibling are both inactive (ie. not pressed/hovered/moved) - bool transient = !opt->activeSubControls && !(slider->state & State_On); - - if (!transient || - oldPos != slider->sliderPosition || - oldMin != slider->minimum || - oldMax != slider->maximum || - oldRect != slider->rect || - oldState != slider->state || - oldActiveControls != slider->activeSubControls) { - - // if the scrollbar is transient or its attributes, geometry or - // state has changed, the opacity is reset back to 100% opaque - opacity = 1.0; - - styleObject->setProperty("_q_stylepos", slider->sliderPosition); - styleObject->setProperty("_q_stylemin", slider->minimum); - styleObject->setProperty("_q_stylemax", slider->maximum); - styleObject->setProperty("_q_stylerect", slider->rect); - styleObject->setProperty("_q_stylestate", static_cast(slider->state)); - styleObject->setProperty("_q_stylecontrols", static_cast(slider->activeSubControls)); - - QScrollbarStyleAnimation *anim = qobject_cast(d->animation(styleObject)); - if (transient) { - if (!anim) { - anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Deactivating, styleObject); - d->startAnimation(anim); - } else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) { - // the scrollbar was already fading out while the - // state changed -> restart the fade out animation - anim->setCurrentTime(0); - } - } else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) { - d->stopAnimation(styleObject); - } - } - - QScrollbarStyleAnimation *anim = qobject_cast(d->animation(styleObject)); - if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) { - // once a scrollbar was active (hovered/pressed), it retains - // the active look even if it's no longer active while fading out - if (oldActiveControls) - anim->setActive(true); - - wasActive = anim->wasActive(); - opacity = anim->currentValue(); - } - - shouldExpand = (opt->activeSubControls || wasActive); - if (shouldExpand) { - if (!anim && !oldActiveControls) { - // Start expand animation only once and when entering - anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Activating, styleObject); - d->startAnimation(anim); - } - if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) { - expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue(); - expandOffset = 5.5 * anim->currentValue() - 1; - } else { - // Keep expanded state after the animation ends, and when fading out - expandScale = maxExpandScale; - expandOffset = 4.5; - } - } - } - - CGContextSaveGState(cg); - [NSGraphicsContext saveGraphicsState]; - - [NSGraphicsContext setCurrentContext:[NSGraphicsContext - graphicsContextWithGraphicsPort:(CGContextRef)cg flipped:NO]]; - NSScroller *scroller = isHorizontal ? d->horizontalScroller : d-> verticalScroller; - // mac os behaviour: as soon as one color channel is >= 128, - // the bg is considered bright, scroller is dark - const QColor bgColor = QStyleHelper::backgroundColor(opt->palette, widget); - const bool isDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && - bgColor.blue() < 128; - if (isDarkBg) - [scroller setKnobStyle:NSScrollerKnobStyleLight]; - else - [scroller setKnobStyle:NSScrollerKnobStyleDefault]; - - [scroller setControlSize:(tdi.kind == kThemeSmallScrollBar ? NSMiniControlSize - : NSRegularControlSize)]; - [scroller setBounds:NSMakeRect(0, 0, slider->rect.width(), slider->rect.height())]; - [scroller setScrollerStyle:NSScrollerStyleOverlay]; - - CGContextBeginTransparencyLayer(cg, NULL); - CGContextSetAlpha(cg, opacity); - - // Draw the track when hovering - if (opt->activeSubControls || wasActive) { - NSRect rect = [scroller bounds]; - if (shouldExpand) { - if (isHorizontal) - rect.origin.y += 4.5 - expandOffset; - else - rect.origin.x += 4.5 - expandOffset; - } - [scroller drawKnobSlotInRect:rect highlight:YES]; - } - - const qreal length = slider->maximum - slider->minimum + slider->pageStep; - const qreal proportion = slider->pageStep / length; - qreal value = (slider->sliderValue - slider->minimum) / length; - if (isHorizontal && slider->direction == Qt::RightToLeft) - value = 1.0 - value - proportion; - - [scroller setKnobProportion:1.0]; - - const int minKnobWidth = 26; - - if (isHorizontal) { - const qreal plannedWidth = proportion * slider->rect.width(); - const qreal width = qMax(minKnobWidth, plannedWidth); - const qreal totalWidth = slider->rect.width() + plannedWidth - width; - [scroller setFrame:NSMakeRect(0, 0, width, slider->rect.height())]; - if (shouldExpand) { - CGContextScaleCTM(cg, 1, expandScale); - CGContextTranslateCTM(cg, value * totalWidth, -expandOffset); - } else { - CGContextTranslateCTM(cg, value * totalWidth, 1); - } - } else { - const qreal plannedHeight = proportion * slider->rect.height(); - const qreal height = qMax(minKnobWidth, plannedHeight); - const qreal totalHeight = slider->rect.height() + plannedHeight - height; - [scroller setFrame:NSMakeRect(0, 0, slider->rect.width(), height)]; - if (shouldExpand) { - CGContextScaleCTM(cg, expandScale, 1); - CGContextTranslateCTM(cg, -expandOffset, value * totalHeight); - } else { - CGContextTranslateCTM(cg, 1, value * totalHeight); - } - } - if (length > 0.0) { - [scroller layout]; - [scroller drawKnob]; - } - - CGContextEndTransparencyLayer(cg); - - [NSGraphicsContext restoreGraphicsState]; - CGContextRestoreGState(cg); - } else { - d->stopAnimation(opt->styleObject); - - if (cc == CC_Slider) { - // Fix min and max positions. (See also getSliderInfo() - // for the slider values adjustments.) - // HITheme seems to have forgotten how to render - // a slide at those positions, leaving a gap between - // the knob and the ends of the track. - // We fix this by rendering the track first, and then - // the knob on top. However, in order to not clip the - // knob, we reduce the the drawing rect for the track. - HIRect bounds = tdi.bounds; - if (isHorizontal) { - tdi.bounds.size.width -= 2; - tdi.bounds.origin.x += 1; - if (tdi.trackInfo.slider.thumbDir == kThemeThumbDownward) - tdi.bounds.origin.y -= 2; - else if (tdi.trackInfo.slider.thumbDir == kThemeThumbUpward) - tdi.bounds.origin.y += 3; - } else { - tdi.bounds.size.height -= 2; - tdi.bounds.origin.y += 1; - if (tdi.trackInfo.slider.thumbDir == kThemeThumbDownward) // pointing right - tdi.bounds.origin.x -= 4; - else if (tdi.trackInfo.slider.thumbDir == kThemeThumbUpward) // pointing left - tdi.bounds.origin.x += 2; - } - - // Yosemite demands its blue progress track when no tickmarks are present - if (!(slider->subControls & SC_SliderTickmarks)) { - QCocoaWidgetKind sliderKind = slider->orientation == Qt::Horizontal ? QCocoaHorizontalSlider : QCocoaVerticalSlider; - QCocoaWidget cw = QCocoaWidget(sliderKind, QAquaSizeLarge); - NSSlider *sl = (NSSlider *)d->cocoaControl(cw); - sl.minValue = slider->minimum; - sl.maxValue = slider->maximum; - sl.intValue = slider->sliderValue; - sl.enabled = slider->state & QStyle::State_Enabled; - d->drawNSViewInRect(cw, sl, opt->rect, p, widget != 0, ^(NSRect rect, CGContextRef ctx) { - const bool isSierraOrLater = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSierra; - if (slider->upsideDown) { - if (isHorizontal) { - CGContextTranslateCTM(ctx, rect.size.width, 0); - CGContextScaleCTM(ctx, -1, 1); - } - } else if (!isHorizontal && !isSierraOrLater) { - CGContextTranslateCTM(ctx, 0, rect.size.height); - CGContextScaleCTM(ctx, 1, -1); - } - const bool shouldFlip = isHorizontal || (slider->upsideDown && isSierraOrLater); - [sl.cell drawBarInside:NSRectFromCGRect(tdi.bounds) flipped:shouldFlip]; - // No need to restore the CTM later, the context has been saved - // and will be restored at the end of drawNSViewInRect() - }); - tdi.attributes |= kThemeTrackHideTrack; - } else { - tdi.attributes &= ~(kThemeTrackShowThumb | kThemeTrackHasFocus); - HIThemeDrawTrack(&tdi, tracking ? 0 : &macRect, cg, - kHIThemeOrientationNormal); - tdi.attributes |= kThemeTrackHideTrack | kThemeTrackShowThumb; - } - - tdi.bounds = bounds; - } - - if (cc == CC_Slider && slider->subControls & SC_SliderTickmarks) { - - HIRect bounds; - // As part of fixing the min and max positions, - // we need to adjust the tickmarks as well - bounds = tdi.bounds; - if (slider->orientation == Qt::Horizontal) { - tdi.bounds.size.width += 2; - tdi.bounds.origin.x -= 1; - if (tdi.trackInfo.slider.thumbDir == kThemeThumbUpward) - tdi.bounds.origin.y -= 2; - } else { - tdi.bounds.size.height += 3; - tdi.bounds.origin.y -= 3; - tdi.bounds.origin.y += 1; - if (tdi.trackInfo.slider.thumbDir == kThemeThumbUpward) // pointing left - tdi.bounds.origin.x -= 2; - } - - if (qt_mac_is_metal(widget)) { - if (tdi.enableState == kThemeTrackInactive) - tdi.enableState = kThemeTrackActive; // Looks more Cocoa-like - } - int interval = slider->tickInterval; - if (interval == 0) { - interval = slider->pageStep; - if (interval == 0) - interval = slider->singleStep; - if (interval == 0) - interval = 1; - } - int numMarks = 1 + ((slider->maximum - slider->minimum) / interval); - - if (tdi.trackInfo.slider.thumbDir == kThemeThumbPlain) { - // They asked for both, so we'll give it to them. - tdi.trackInfo.slider.thumbDir = kThemeThumbDownward; - HIThemeDrawTrackTickMarks(&tdi, numMarks, - cg, - kHIThemeOrientationNormal); - tdi.trackInfo.slider.thumbDir = kThemeThumbUpward; - // 10.10 and above need a slight shift - if (slider->orientation == Qt::Vertical) - tdi.bounds.origin.x -= 2; - HIThemeDrawTrackTickMarks(&tdi, numMarks, - cg, - kHIThemeOrientationNormal); - // Reset to plain thumb to be drawn further down - tdi.trackInfo.slider.thumbDir = kThemeThumbPlain; - } else { - HIThemeDrawTrackTickMarks(&tdi, numMarks, - cg, - kHIThemeOrientationNormal); - } - - tdi.bounds = bounds; - } - - if (cc == CC_Slider) { - // Still as part of fixing the min and max positions, - // we also adjust the knob position. We can do this - // because it's rendered separately from the track. - if (slider->orientation == Qt::Vertical) { - if (tdi.trackInfo.slider.thumbDir == kThemeThumbDownward) // pointing right - tdi.bounds.origin.x -= 2; - } - } - - HIThemeDrawTrack(&tdi, tracking ? 0 : &macRect, cg, - kHIThemeOrientationNormal); - } - } - break; -#if QT_CONFIG(spinbox) - case CC_SpinBox: - if (const QStyleOptionSpinBox *sb = qstyleoption_cast(opt)) { - QStyleOptionSpinBox newSB = *sb; - if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) { - SInt32 frame_size; - GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size); - - QRect lineeditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget); - lineeditRect.adjust(-frame_size, -frame_size, +frame_size, +frame_size); - - HIThemeFrameDrawInfo fdi; - fdi.version = qt_mac_hitheme_version; - fdi.state = tds == kThemeStateInactive ? kThemeStateActive : tds; - fdi.kind = kHIThemeFrameTextFieldSquare; - fdi.isFocused = false; - HIRect hirect = qt_hirectForQRect(lineeditRect); - HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal); - } - if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) { - HIThemeButtonDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - QAquaWidgetSize aquaSize = d->aquaSizeConstrain(opt, widget); - switch (aquaSize) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - bdi.kind = kThemeIncDecButton; - break; - case QAquaSizeMini: - bdi.kind = kThemeIncDecButtonMini; - break; - case QAquaSizeSmall: - bdi.kind = kThemeIncDecButtonSmall; - break; - } - if (!(sb->stepEnabled & (QAbstractSpinBox::StepUpEnabled - | QAbstractSpinBox::StepDownEnabled))) - tds = kThemeStateUnavailable; - if (sb->activeSubControls == SC_SpinBoxDown - && (sb->state & State_Sunken)) - tds = kThemeStatePressedDown; - else if (sb->activeSubControls == SC_SpinBoxUp - && (sb->state & State_Sunken)) - tds = kThemeStatePressedUp; - if (tds == kThemeStateInactive) - bdi.state = kThemeStateActive; - else - bdi.state = tds; - bdi.value = kThemeButtonOff; - bdi.adornment = kThemeAdornmentNone; - - QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget); - - updown |= proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget); - HIRect newRect = qt_hirectForQRect(updown); - QRect off_rct; - HIRect outRect; - HIThemeGetButtonBackgroundBounds(&newRect, &bdi, &outRect); - off_rct.setRect(int(newRect.origin.x - outRect.origin.x), - int(newRect.origin.y - outRect.origin.y), - int(outRect.size.width - newRect.size.width), - int(outRect.size.height - newRect.size.height)); - - newRect = qt_hirectForQRect(updown, off_rct); - if (tds == kThemeStateInactive) - d->drawColorlessButton(newRect, &bdi, p, sb); - else - HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0); - } - } - break; -#endif - case CC_ComboBox: - if (const QStyleOptionComboBox *combo = qstyleoption_cast(opt)){ - HIThemeButtonDrawInfo bdi; - d->initComboboxBdi(combo, &bdi, widget, tds); - HIRect rect = qt_hirectForQRect(combo->rect); - if (combo->editable) - rect.origin.y += tds == kThemeStateInactive ? 1 : 2; - if (tds != kThemeStateInactive) - QMacStylePrivate::drawCombobox(rect, bdi, p); - else if (!widget && combo->editable) { - QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind); - NSView *cb = d->cocoaControl(cw); - QRect r = combo->rect.adjusted(3, 0, 0, 0); - d->drawNSViewInRect(cw, cb, r, p, widget != 0); - } else - d->drawColorlessButton(rect, &bdi, p, opt); - } - break; - case CC_TitleBar: - if (const QStyleOptionTitleBar *titlebar - = qstyleoption_cast(opt)) { - if (titlebar->state & State_Active) { - if (titlebar->titleBarState & State_Active) - tds = kThemeStateActive; - else - tds = kThemeStateInactive; - } else { - tds = kThemeStateInactive; - } - - HIThemeWindowDrawInfo wdi; - wdi.version = qt_mac_hitheme_version; - wdi.state = tds; - wdi.windowType = QtWinType; - wdi.titleHeight = titlebar->rect.height(); - wdi.titleWidth = titlebar->rect.width(); - wdi.attributes = kThemeWindowHasTitleText; - // It seems HIThemeDrawTitleBarWidget is not able to draw a dirty - // close button, so use HIThemeDrawWindowFrame instead. - if (widget && widget->isWindowModified() && titlebar->subControls & SC_TitleBarCloseButton) - wdi.attributes |= kThemeWindowHasCloseBox | kThemeWindowHasDirty; - - HIRect titleBarRect; - HIRect tmpRect = qt_hirectForQRect(titlebar->rect); - { - QCFType titleRegion; - QRect newr = titlebar->rect.adjusted(0, 0, 2, 0); - HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion); - ptrHIShapeGetBounds(titleRegion, &tmpRect); - newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y)); - titleBarRect = qt_hirectForQRect(newr); - } - HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0); - if (titlebar->subControls & (SC_TitleBarCloseButton - | SC_TitleBarMaxButton - | SC_TitleBarMinButton - | SC_TitleBarNormalButton)) { - HIThemeWindowWidgetDrawInfo wwdi; - wwdi.version = qt_mac_hitheme_version; - wwdi.widgetState = tds; - if (titlebar->state & State_MouseOver) - wwdi.widgetState = kThemeStateRollover; - wwdi.windowType = QtWinType; - wwdi.attributes = wdi.attributes | kThemeWindowHasFullZoom | kThemeWindowHasCloseBox | kThemeWindowHasCollapseBox; - wwdi.windowState = wdi.state; - wwdi.titleHeight = wdi.titleHeight; - wwdi.titleWidth = wdi.titleWidth; - ThemeDrawState savedControlState = wwdi.widgetState; - uint sc = SC_TitleBarMinButton; - ThemeTitleBarWidget tbw = kThemeWidgetCollapseBox; - bool active = titlebar->state & State_Active; - - while (sc <= SC_TitleBarCloseButton) { - if (sc & titlebar->subControls) { - uint tmp = sc; - wwdi.widgetState = savedControlState; - wwdi.widgetType = tbw; - if (sc == SC_TitleBarMinButton) - tmp |= SC_TitleBarNormalButton; - if (active && (titlebar->activeSubControls & tmp) - && (titlebar->state & State_Sunken)) - wwdi.widgetState = kThemeStatePressed; - // Draw all sub controllers except the dirty close button - // (it is already handled by HIThemeDrawWindowFrame). - if (!(widget && widget->isWindowModified() && tbw == kThemeWidgetCloseBox)) { - HIThemeDrawTitleBarWidget(&titleBarRect, &wwdi, cg, kHIThemeOrientationNormal); - p->paintEngine()->syncState(); - } - } - sc = sc << 1; - tbw = tbw >> 1; - } - } - p->paintEngine()->syncState(); - if (titlebar->subControls & SC_TitleBarLabel) { - int iw = 0; - if (!titlebar->icon.isNull()) { - QCFType titleRegion2; - HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleProxyIconRgn, - &titleRegion2); - ptrHIShapeGetBounds(titleRegion2, &tmpRect); - if (tmpRect.size.width != 1) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); - iw = titlebar->icon.actualSize(QSize(iconExtent, iconExtent)).width(); - } - } - if (!titlebar->text.isEmpty()) { - p->save(); - QCFType titleRegion3; - HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleTextRgn, &titleRegion3); - ptrHIShapeGetBounds(titleRegion3, &tmpRect); - p->setClipRect(qt_qrectForHIRect(tmpRect)); - QRect br = p->clipRegion().boundingRect(); - int x = br.x(), - y = br.y() + (titlebar->rect.height() / 2 - p->fontMetrics().height() / 2); - if (br.width() <= (p->fontMetrics().width(titlebar->text) + iw * 2)) - x += iw; - else - x += br.width() / 2 - p->fontMetrics().width(titlebar->text) / 2; - if (iw) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); - p->drawPixmap(x - iw, y, - titlebar->icon.pixmap(window, QSize(iconExtent, iconExtent), QIcon::Normal)); - } - drawItemText(p, br, Qt::AlignCenter, opt->palette, tds == kThemeStateActive, - titlebar->text, QPalette::Text); - p->restore(); - } - } - } - break; - case CC_GroupBox: - if (const QStyleOptionGroupBox *gb - = qstyleoption_cast(opt)) { - - QStyleOptionGroupBox groupBox(*gb); - const bool flat = groupBox.features & QStyleOptionFrame::Flat; - if (!flat) - groupBox.state |= QStyle::State_Mini; // Force mini-sized checkbox to go with small-sized label - else - groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame; // We don't like frames and ugly lines - - bool didModifySubControls = false; - if ((!widget || !widget->testAttribute(Qt::WA_SetFont)) - && QApplication::desktopSettingsAware()) { - groupBox.subControls = groupBox.subControls & ~SC_GroupBoxLabel; - didModifySubControls = true; - } - QCommonStyle::drawComplexControl(cc, &groupBox, p, widget); - if (didModifySubControls) { - p->save(); - CGContextSetShouldAntialias(cg, true); - CGContextSetShouldSmoothFonts(cg, true); - HIThemeTextInfo tti; - tti.version = qt_mac_hitheme_version; - tti.state = tds; - QColor textColor = groupBox.palette.windowText().color(); - CGFloat colorComp[] = { static_cast(textColor.redF()), static_cast(textColor.greenF()), - static_cast(textColor.blueF()), static_cast(textColor.alphaF()) }; - CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace()); - CGContextSetFillColor(cg, colorComp); - tti.fontID = flat ? kThemeSystemFont : kThemeSmallSystemFont; - tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter; - tti.verticalFlushness = kHIThemeTextVerticalFlushCenter; - tti.options = kHIThemeTextBoxOptionNone; - tti.truncationPosition = kHIThemeTextTruncationNone; - tti.truncationMaxLines = 1 + groupBox.text.count(QLatin1Char('\n')); - QCFString groupText = qt_mac_removeMnemonics(groupBox.text); - QRect r = proxy()->subControlRect(CC_GroupBox, &groupBox, SC_GroupBoxLabel, widget); - HIRect bounds = qt_hirectForQRect(r); - HIThemeDrawTextBox(groupText, &bounds, &tti, cg, kHIThemeOrientationNormal); - p->restore(); - } - } - break; - case CC_ToolButton: - if (const QStyleOptionToolButton *tb - = qstyleoption_cast(opt)) { -#ifndef QT_NO_ACCESSIBILITY - if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) { - if (tb->subControls & SC_ToolButtonMenu) { - QStyleOption arrowOpt = *tb; - arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget); - arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2); - arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2); - proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget); - } else if ((tb->features & QStyleOptionToolButton::HasMenu) - && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) { - drawToolbarButtonArrow(tb->rect, tds, cg); - } - if (tb->state & State_On) { - QWindow *window = 0; - if (widget && widget->window()) - window = widget->window()->windowHandle(); - else if (opt->styleObject) - window = opt->styleObject->property("_q_styleObjectWindow").value(); - - NSView *view = window ? (NSView *)window->winId() : nil; - bool isKey = false; - if (view) - isKey = [view.window isKeyWindow]; - - QBrush brush(isKey ? QColor(0, 0, 0, 28) - : QColor(0, 0, 0, 21)); - QPainterPath path; - path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4); - p->setRenderHint(QPainter::Antialiasing); - p->fillPath(path, brush); - } - proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget); - } else { - ThemeButtonKind bkind = kThemeBevelButton; - switch (d->aquaSizeConstrain(opt, widget)) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - bkind = kThemeBevelButton; - break; - case QAquaSizeMini: - case QAquaSizeSmall: - bkind = kThemeSmallBevelButton; - break; - } - - QRect button, menuarea; - button = proxy()->subControlRect(cc, tb, SC_ToolButton, widget); - menuarea = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget); - State bflags = tb->state, - mflags = tb->state; - if (tb->subControls & SC_ToolButton) - bflags |= State_Sunken; - if (tb->subControls & SC_ToolButtonMenu) - mflags |= State_Sunken; - - if (tb->subControls & SC_ToolButton) { - if (bflags & (State_Sunken | State_On | State_Raised)) { - HIThemeButtonDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - bdi.state = tds; - bdi.adornment = kThemeAdornmentNone; - bdi.kind = bkind; - bdi.value = kThemeButtonOff; - if (tb->state & State_HasFocus) - bdi.adornment = kThemeAdornmentFocus; - if (tb->state & State_Sunken) - bdi.state = kThemeStatePressed; - if (tb->state & State_On) - bdi.value = kThemeButtonOn; - - QRect off_rct(0, 0, 0, 0); - HIRect myRect, macRect; - myRect = CGRectMake(tb->rect.x(), tb->rect.y(), - tb->rect.width(), tb->rect.height()); - HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect); - off_rct.setRect(int(myRect.origin.x - macRect.origin.x), - int(myRect.origin.y - macRect.origin.y), - int(macRect.size.width - myRect.size.width), - int(macRect.size.height - myRect.size.height)); - - myRect = qt_hirectForQRect(button, off_rct); - HIThemeDrawButton(&myRect, &bdi, cg, kHIThemeOrientationNormal, 0); - } - } - - if (tb->subControls & SC_ToolButtonMenu) { - HIThemeButtonDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - bdi.state = tds; - bdi.value = kThemeButtonOff; - bdi.adornment = kThemeAdornmentNone; - bdi.kind = bkind; - if (tb->state & State_HasFocus) - bdi.adornment = kThemeAdornmentFocus; - if (tb->state & (State_On | State_Sunken) - || (tb->activeSubControls & SC_ToolButtonMenu)) - bdi.state = kThemeStatePressed; - HIRect hirect = qt_hirectForQRect(menuarea); - HIThemeDrawButton(&hirect, &bdi, cg, kHIThemeOrientationNormal, 0); - QRect r(menuarea.x() + ((menuarea.width() / 2) - 3), menuarea.height() - 8, 8, 8); - HIThemePopupArrowDrawInfo padi; - padi.version = qt_mac_hitheme_version; - padi.state = tds; - padi.orientation = kThemeArrowDown; - padi.size = kThemeArrow7pt; - hirect = qt_hirectForQRect(r); - HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal); - } else if (tb->features & QStyleOptionToolButton::HasMenu) { - drawToolbarButtonArrow(tb->rect, tds, cg); - } - QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton, widget); - int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget); - QStyleOptionToolButton label = *tb; - label.rect = buttonRect.adjusted(fw, fw, -fw, -fw); - proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget); - } -#endif - } - break; -#if QT_CONFIG(dial) - case CC_Dial: - if (const QStyleOptionSlider *dial = qstyleoption_cast(opt)) - QStyleHelper::drawDial(dial, p); - break; -#endif - default: - QCommonStyle::drawComplexControl(cc, opt, p, widget); - break; - } -} - -QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc, - const QStyleOptionComplex *opt, - const QPoint &pt, const QWidget *widget) const -{ - Q_D(const QMacStyle); - SubControl sc = QStyle::SC_None; - switch (cc) { - case CC_ComboBox: - if (const QStyleOptionComboBox *cmb = qstyleoption_cast(opt)) { - sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt, widget); - if (!cmb->editable && sc != QStyle::SC_None) - sc = SC_ComboBoxArrow; // A bit of a lie, but what we want - } - break; - case CC_Slider: - if (const QStyleOptionSlider *slider = qstyleoption_cast(opt)) { - HIThemeTrackDrawInfo tdi; - d->getSliderInfo(cc, slider, &tdi, widget); - ControlPartCode part; - HIPoint pos = CGPointMake(pt.x(), pt.y()); - if (HIThemeHitTestTrack(&tdi, &pos, &part)) { - if (part == kControlPageUpPart || part == kControlPageDownPart) - sc = SC_SliderGroove; - else - sc = SC_SliderHandle; - } - } - break; - case CC_ScrollBar: - if (const QStyleOptionSlider *sb = qstyleoption_cast(opt)) { - HIScrollBarTrackInfo sbi; - sbi.version = qt_mac_hitheme_version; - if (!(sb->state & State_Active)) - sbi.enableState = kThemeTrackInactive; - else if (sb->state & State_Enabled) - sbi.enableState = kThemeTrackActive; - else - sbi.enableState = kThemeTrackDisabled; - - // The arrow buttons are not drawn if the scroll bar is to short, - // exclude them from the hit test. - const int scrollBarLength = (sb->orientation == Qt::Horizontal) - ? sb->rect.width() : sb->rect.height(); - if (scrollBarLength < scrollButtonsCutoffSize(scrollButtonsCutoff, widgetSizePolicy(widget, opt))) - sbi.enableState = kThemeTrackNothingToScroll; - - sbi.viewsize = sb->pageStep; - HIPoint pos = CGPointMake(pt.x(), pt.y()); - - HIRect macSBRect = qt_hirectForQRect(sb->rect); - ControlPartCode part; - bool reverseHorizontal = (sb->direction == Qt::RightToLeft - && sb->orientation == Qt::Horizontal); - if (HIThemeHitTestScrollBarArrows(&macSBRect, &sbi, sb->orientation == Qt::Horizontal, - &pos, 0, &part)) { - if (part == kControlUpButtonPart) - sc = reverseHorizontal ? SC_ScrollBarAddLine : SC_ScrollBarSubLine; - else if (part == kControlDownButtonPart) - sc = reverseHorizontal ? SC_ScrollBarSubLine : SC_ScrollBarAddLine; - } else { - HIThemeTrackDrawInfo tdi; - d->getSliderInfo(cc, sb, &tdi, widget); - if(tdi.enableState == kThemeTrackInactive) - tdi.enableState = kThemeTrackActive; - if (HIThemeHitTestTrack(&tdi, &pos, &part)) { - if (part == kControlPageUpPart) - sc = reverseHorizontal ? SC_ScrollBarAddPage - : SC_ScrollBarSubPage; - else if (part == kControlPageDownPart) - sc = reverseHorizontal ? SC_ScrollBarSubPage - : SC_ScrollBarAddPage; - else - sc = SC_ScrollBarSlider; - } - } - } - break; -/* - I don't know why, but we only get kWindowContentRgn here, which isn't what we want at all. - It would be very nice if this would work. - case QStyle::CC_TitleBar: - if (const QStyleOptionTitleBar *tbar = qstyleoption_cast(opt)) { - HIThemeWindowDrawInfo wdi; - memset(&wdi, 0, sizeof(wdi)); - wdi.version = qt_mac_hitheme_version; - wdi.state = kThemeStateActive; - wdi.windowType = QtWinType; - wdi.titleWidth = tbar->rect.width(); - wdi.titleHeight = tbar->rect.height(); - if (tbar->titleBarState) - wdi.attributes |= kThemeWindowHasFullZoom | kThemeWindowHasCloseBox - | kThemeWindowHasCollapseBox; - else if (tbar->titleBarFlags & Qt::WindowSystemMenuHint) - wdi.attributes |= kThemeWindowHasCloseBox; - QRect tmpRect = tbar->rect; - tmpRect.setHeight(tmpRect.height() + 100); - HIRect hirect = qt_hirectForQRect(tmpRect); - WindowRegionCode hit; - HIPoint hipt = CGPointMake(pt.x(), pt.y()); - if (HIThemeGetWindowRegionHit(&hirect, &wdi, &hipt, &hit)) { - switch (hit) { - case kWindowCloseBoxRgn: - sc = QStyle::SC_TitleBarCloseButton; - break; - case kWindowCollapseBoxRgn: - sc = QStyle::SC_TitleBarMinButton; - break; - case kWindowZoomBoxRgn: - sc = QStyle::SC_TitleBarMaxButton; - break; - case kWindowTitleTextRgn: - sc = QStyle::SC_TitleBarLabel; - break; - default: - qDebug("got something else %d", hit); - break; - } - } - } - break; -*/ - default: - sc = QCommonStyle::hitTestComplexControl(cc, opt, pt, widget); - break; - } - return sc; -} - -QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, - const QWidget *widget) const -{ - Q_D(const QMacStyle); - QRect ret; - switch (cc) { - case CC_Slider: - case CC_ScrollBar: - if (const QStyleOptionSlider *slider = qstyleoption_cast(opt)) { - HIThemeTrackDrawInfo tdi; - d->getSliderInfo(cc, slider, &tdi, widget); - HIRect macRect; - QCFType shape; - bool scrollBar = cc == CC_ScrollBar; - if ((scrollBar && sc == SC_ScrollBarSlider) - || (!scrollBar && sc == SC_SliderHandle)) { - HIThemeGetTrackThumbShape(&tdi, &shape); - ptrHIShapeGetBounds(shape, &macRect); - } else if (!scrollBar && sc == SC_SliderGroove) { - HIThemeGetTrackBounds(&tdi, &macRect); - } else if (sc == SC_ScrollBarGroove) { // Only scroll bar parts available... - HIThemeGetTrackDragRect(&tdi, &macRect); - } else { - ControlPartCode cpc; - if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) { - cpc = sc == SC_ScrollBarSubPage ? kControlPageDownPart - : kControlPageUpPart; - } else { - cpc = sc == SC_ScrollBarSubLine ? kControlUpButtonPart - : kControlDownButtonPart; - if (slider->direction == Qt::RightToLeft - && slider->orientation == Qt::Horizontal) { - if (cpc == kControlDownButtonPart) - cpc = kControlUpButtonPart; - else if (cpc == kControlUpButtonPart) - cpc = kControlDownButtonPart; - } - } - HIThemeGetTrackPartBounds(&tdi, cpc, &macRect); - } - ret = qt_qrectForHIRect(macRect); - - // Tweak: the dark line between the sub/add line buttons belong to only one of the buttons - // when doing hit-testing, but both of them have to repaint it. Extend the rect to cover - // the line in the cases where HIThemeGetTrackPartBounds returns a rect that doesn't. - if (slider->orientation == Qt::Horizontal) { - if (slider->direction == Qt::LeftToRight && sc == SC_ScrollBarSubLine) - ret.adjust(0, 0, 1, 0); - else if (slider->direction == Qt::RightToLeft && sc == SC_ScrollBarAddLine) - ret.adjust(-1, 0, 1, 0); - } else if (sc == SC_ScrollBarAddLine) { - ret.adjust(0, -1, 0, 1); - } - } - break; - case CC_TitleBar: - if (const QStyleOptionTitleBar *titlebar - = qstyleoption_cast(opt)) { - HIThemeWindowDrawInfo wdi; - memset(&wdi, 0, sizeof(wdi)); - wdi.version = qt_mac_hitheme_version; - wdi.state = kThemeStateActive; - wdi.windowType = QtWinType; - wdi.titleHeight = titlebar->rect.height(); - wdi.titleWidth = titlebar->rect.width(); - wdi.attributes = kThemeWindowHasTitleText; - if (titlebar->subControls & SC_TitleBarCloseButton) - wdi.attributes |= kThemeWindowHasCloseBox; - if (titlebar->subControls & SC_TitleBarMaxButton - | SC_TitleBarNormalButton) - wdi.attributes |= kThemeWindowHasFullZoom; - if (titlebar->subControls & SC_TitleBarMinButton) - wdi.attributes |= kThemeWindowHasCollapseBox; - WindowRegionCode wrc = kWindowGlobalPortRgn; - - if (sc == SC_TitleBarCloseButton) - wrc = kWindowCloseBoxRgn; - else if (sc == SC_TitleBarMinButton) - wrc = kWindowCollapseBoxRgn; - else if (sc == SC_TitleBarMaxButton) - wrc = kWindowZoomBoxRgn; - else if (sc == SC_TitleBarLabel) - wrc = kWindowTitleTextRgn; - else if (sc == SC_TitleBarSysMenu) - ret.setRect(-1024, -1024, 10, proxy()->pixelMetric(PM_TitleBarHeight, - titlebar, widget)); - if (wrc != kWindowGlobalPortRgn) { - QCFType region; - QRect tmpRect = titlebar->rect; - HIRect titleRect = qt_hirectForQRect(tmpRect); - HIThemeGetWindowShape(&titleRect, &wdi, kWindowTitleBarRgn, ®ion); - ptrHIShapeGetBounds(region, &titleRect); - CFRelease(region); - tmpRect.translate(tmpRect.x() - int(titleRect.origin.x), - tmpRect.y() - int(titleRect.origin.y)); - titleRect = qt_hirectForQRect(tmpRect); - HIThemeGetWindowShape(&titleRect, &wdi, wrc, ®ion); - ptrHIShapeGetBounds(region, &titleRect); - ret = qt_qrectForHIRect(titleRect); - } - } - break; - case CC_ComboBox: - if (const QStyleOptionComboBox *combo = qstyleoption_cast(opt)) { - HIThemeButtonDrawInfo bdi; - d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state)); - - switch (sc) { - case SC_ComboBoxEditField:{ - ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi); - // 10.10 and above need a slight shift - ret.setHeight(ret.height() - 1); - break; } - case SC_ComboBoxArrow:{ - ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi); - ret.setX(ret.x() + ret.width()); - ret.setWidth(combo->rect.right() - ret.right()); - break; } - case SC_ComboBoxListBoxPopup:{ - if (combo->editable) { - HIRect inner = QMacStylePrivate::comboboxInnerBounds(qt_hirectForQRect(combo->rect), bdi.kind); - QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi); - const int comboTop = combo->rect.top(); - ret = QRect(qRound(inner.origin.x), - comboTop, - qRound(inner.origin.x - combo->rect.left() + inner.size.width), - editRect.bottom() - comboTop + 2); - } else { - QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi); - ret = QRect(combo->rect.x() + 4 - 11, - combo->rect.y() + 1, - editRect.width() + 10 + 11, - 1); - } - break; } - default: - break; - } - } - break; - case CC_GroupBox: - if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(opt)) { - bool checkable = groupBox->subControls & SC_GroupBoxCheckBox; - const bool flat = groupBox->features & QStyleOptionFrame::Flat; - bool hasNoText = !checkable && groupBox->text.isEmpty(); - switch (sc) { - case SC_GroupBoxLabel: - case SC_GroupBoxCheckBox: { - // Cheat and use the smaller font if we need to - bool checkable = groupBox->subControls & SC_GroupBoxCheckBox; - bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont)) - || !QApplication::desktopSettingsAware(); - int tw; - int h; - int margin = flat || hasNoText ? 0 : 9; - ret = groupBox->rect.adjusted(margin, 0, -margin, 0); - - if (!fontIsSet) { - HIThemeTextInfo tti; - tti.version = qt_mac_hitheme_version; - tti.state = kThemeStateActive; - tti.fontID = flat ? kThemeSystemFont : kThemeSmallSystemFont; - tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter; - tti.verticalFlushness = kHIThemeTextVerticalFlushCenter; - tti.options = kHIThemeTextBoxOptionNone; - tti.truncationPosition = kHIThemeTextTruncationNone; - tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n')); - CGFloat width; - CGFloat height; - QCFString groupText = qt_mac_removeMnemonics(groupBox->text); - HIThemeGetTextDimensions(groupText, 0, &tti, &width, &height, 0); - tw = qRound(width); - h = qCeil(height); - } else { - QFontMetricsF fm = QFontMetricsF(groupBox->fontMetrics); - h = qCeil(fm.height()); - tw = qCeil(fm.size(Qt::TextShowMnemonic, groupBox->text).width()); - } - ret.setHeight(h); - - QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment, - QSize(tw, h), ret); - if (flat && checkable) - labelRect.moveLeft(labelRect.left() + 4); - int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt, widget); - bool rtl = groupBox->direction == Qt::RightToLeft; - if (sc == SC_GroupBoxLabel) { - if (checkable) { - int newSum = indicatorWidth + 1; - int newLeft = labelRect.left() + (rtl ? -newSum : newSum); - labelRect.moveLeft(newLeft); - if (flat) - labelRect.moveTop(labelRect.top() + 3); - else - labelRect.moveTop(labelRect.top() + 4); - } else if (flat) { - int newLeft = labelRect.left() - (rtl ? 3 : -3); - labelRect.moveLeft(newLeft); - labelRect.moveTop(labelRect.top() + 3); - } else { - int newLeft = labelRect.left() - (rtl ? 3 : 2); - labelRect.moveLeft(newLeft); - labelRect.moveTop(labelRect.top() + 4); - } - ret = labelRect; - } - - if (sc == SC_GroupBoxCheckBox) { - int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1; - int top = flat ? ret.top() + 1 : ret.top() + 5; - ret.setRect(left, top, - indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt, widget)); - } - break; - } - case SC_GroupBoxContents: - case SC_GroupBoxFrame: { - QFontMetrics fm = groupBox->fontMetrics; - int yOffset = 3; - if (!flat) { - if (widget && !widget->testAttribute(Qt::WA_SetFont) - && QApplication::desktopSettingsAware()) - fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont())); - yOffset = 5; - } - - if (hasNoText) - yOffset = -qCeil(QFontMetricsF(fm).height()); - ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0); - if (sc == SC_GroupBoxContents) { - if (flat) - ret.adjust(3, -5, -3, -4); // guess too - else - ret.adjust(3, 3, -3, -4); // guess - } - } - break; - default: - ret = QCommonStyle::subControlRect(cc, groupBox, sc, widget); - break; - } - } - break; -#if QT_CONFIG(spinbox) - case CC_SpinBox: - if (const QStyleOptionSpinBox *spin = qstyleoption_cast(opt)) { - QAquaWidgetSize aquaSize = d->aquaSizeConstrain(spin, widget); - int spinner_w; - int spinBoxSep; - int fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin, widget); - switch (aquaSize) { - default: - case QAquaSizeUnknown: - case QAquaSizeLarge: - spinner_w = 14; - spinBoxSep = 2; - break; - case QAquaSizeSmall: - spinner_w = 12; - spinBoxSep = 2; - break; - case QAquaSizeMini: - spinner_w = 10; - spinBoxSep = 1; - break; - } - - switch (sc) { - case SC_SpinBoxUp: - case SC_SpinBoxDown: { - if (spin->buttonSymbols == QAbstractSpinBox::NoButtons) - break; - - const int y = fw; - const int x = spin->rect.width() - spinner_w; - ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2); - HIThemeButtonDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - bdi.kind = kThemeIncDecButton; - int hackTranslateX; - switch (aquaSize) { - default: - case QAquaSizeUnknown: - case QAquaSizeLarge: - bdi.kind = kThemeIncDecButton; - hackTranslateX = 0; - break; - case QAquaSizeSmall: - bdi.kind = kThemeIncDecButtonSmall; - hackTranslateX = -2; - break; - case QAquaSizeMini: - bdi.kind = kThemeIncDecButtonMini; - hackTranslateX = -1; - break; - } - bdi.state = kThemeStateActive; - bdi.value = kThemeButtonOff; - bdi.adornment = kThemeAdornmentNone; - HIRect hirect = qt_hirectForQRect(ret); - - HIRect outRect; - HIThemeGetButtonBackgroundBounds(&hirect, &bdi, &outRect); - ret = qt_qrectForHIRect(outRect); - switch (sc) { - case SC_SpinBoxUp: - ret.setHeight(ret.height() / 2); - break; - case SC_SpinBoxDown: - ret.setY(ret.y() + ret.height() / 2); - break; - default: - Q_ASSERT(0); - break; - } - ret.translate(hackTranslateX, 0); // hack: position the buttons correctly (weird that we need this) - ret = visualRect(spin->direction, spin->rect, ret); - break; - } - case SC_SpinBoxEditField: - if (spin->buttonSymbols == QAbstractSpinBox::NoButtons) { - ret.setRect(fw, fw, - spin->rect.width() - fw * 2, - spin->rect.height() - fw * 2); - } else { - ret.setRect(fw, fw, - spin->rect.width() - fw * 2 - spinBoxSep - spinner_w, - spin->rect.height() - fw * 2); - } - ret = visualRect(spin->direction, spin->rect, ret); - break; - default: - ret = QCommonStyle::subControlRect(cc, spin, sc, widget); - break; - } - } - break; -#endif - case CC_ToolButton: - ret = QCommonStyle::subControlRect(cc, opt, sc, widget); - if (sc == SC_ToolButtonMenu -#ifndef QT_NO_ACCESSIBILITY - && !QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar) -#endif - ) { - ret.adjust(-1, 0, 0, 0); - } - break; - default: - ret = QCommonStyle::subControlRect(cc, opt, sc, widget); - break; - } - return ret; -} - -QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, - const QSize &csz, const QWidget *widget) const -{ - Q_D(const QMacStyle); - QSize sz(csz); - bool useAquaGuideline = true; - - switch (ct) { -#if QT_CONFIG(spinbox) - case CT_SpinBox: - if (const QStyleOptionSpinBox *vopt = qstyleoption_cast(opt)) { - // Add button + frame widths - int buttonWidth = 20; - int fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, vopt, widget); - sz += QSize(buttonWidth + 2*fw, 2*fw - 3); - } - break; -#endif - case QStyle::CT_TabWidget: - // the size between the pane and the "contentsRect" (+4,+4) - // (the "contentsRect" is on the inside of the pane) - sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); - /** - This is supposed to show the relationship between the tabBar and - the stack widget of a QTabWidget. - Unfortunately ascii is not a good way of representing graphics..... - PS: The '=' line is the painted frame. - - top ---+ - | - | - | - | vvv just outside the painted frame is the "pane" - - -|- - - - - - - - - - <-+ - TAB BAR +=====^============ | +2 pixels - - - -|- - -|- - - - - - - <-+ - | | ^ ^^^ just inside the painted frame is the "contentsRect" - | | | - | overlap | - | | | - bottom ------+ <-+ +14 pixels - | - v - ------------------------------ <- top of stack widget - - - To summarize: - * 2 is the distance between the pane and the contentsRect - * The 14 and the 1's are the distance from the contentsRect to the stack widget. - (same value as used in SE_TabWidgetTabContents) - * overlap is how much the pane should overlap the tab bar - */ - // then add the size between the stackwidget and the "contentsRect" -#if QT_CONFIG(tabwidget) - if (const QStyleOptionTabWidgetFrame *twf - = qstyleoption_cast(opt)) { - QSize extra(0,0); - const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt, widget); - const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap; - - if (getTabDirection(twf->shape) == kThemeTabNorth || getTabDirection(twf->shape) == kThemeTabSouth) { - extra = QSize(2, gapBetweenTabbarAndStackWidget + 1); - } else { - extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2); - } - sz+= extra; - } -#endif - break; -#if QT_CONFIG(tabbar) - case QStyle::CT_TabBarTab: - if (const QStyleOptionTab *tab = qstyleoption_cast(opt)) { - const QAquaWidgetSize AquaSize = d->aquaSizeConstrain(opt, widget); - const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont)) - || !QApplication::desktopSettingsAware(); - ThemeTabDirection ttd = getTabDirection(tab->shape); - bool vertTabs = ttd == kThemeTabWest || ttd == kThemeTabEast; - if (vertTabs) - sz = sz.transposed(); - int defaultTabHeight; - int extraHSpace = proxy()->pixelMetric(PM_TabBarTabHSpace, tab, widget); - QFontMetrics fm = opt->fontMetrics; - switch (AquaSize) { - case QAquaSizeUnknown: - case QAquaSizeLarge: - if (tab->documentMode) - defaultTabHeight = 24; - else - defaultTabHeight = 21; - break; - case QAquaSizeSmall: - defaultTabHeight = 18; - break; - case QAquaSizeMini: - defaultTabHeight = 16; - break; - } - bool setWidth = false; - if (differentFont || !tab->icon.isNull()) { - sz.rheight() = qMax(defaultTabHeight, sz.height()); - } else { - QSize textSize = fm.size(Qt::TextShowMnemonic, tab->text); - sz.rheight() = qMax(defaultTabHeight, textSize.height()); - sz.rwidth() = textSize.width(); - setWidth = true; - } - sz.rwidth() += extraHSpace; - - if (vertTabs) - sz = sz.transposed(); - - int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height()); - int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width()); - - int widgetWidth = 0; - int widgetHeight = 0; - int padding = 0; - if (tab->leftButtonSize.isValid()) { - padding += 8; - widgetWidth += tab->leftButtonSize.width(); - widgetHeight += tab->leftButtonSize.height(); - } - if (tab->rightButtonSize.isValid()) { - padding += 8; - widgetWidth += tab->rightButtonSize.width(); - widgetHeight += tab->rightButtonSize.height(); - } - - if (vertTabs) { - sz.setHeight(sz.height() + widgetHeight + padding); - sz.setWidth(qMax(sz.width(), maxWidgetWidth)); - } else { - if (setWidth) - sz.setWidth(sz.width() + widgetWidth + padding); - sz.setHeight(qMax(sz.height(), maxWidgetHeight)); - } - } - break; -#endif - case QStyle::CT_PushButton: - // By default, we fit the contents inside a normal rounded push button. - // Do this by add enough space around the contents so that rounded - // borders (including highlighting when active) will show. - sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12; - if (opt->state & QStyle::State_Small) - sz.rheight() += 14; - else - sz.rheight() += 4; - break; - case QStyle::CT_MenuItem: - if (const QStyleOptionMenuItem *mi = qstyleoption_cast(opt)) { - int maxpmw = mi->maxIconWidth; -#if QT_CONFIG(combobox) - const QComboBox *comboBox = qobject_cast(widget); -#endif - int w = sz.width(), - h = sz.height(); - if (mi->menuItemType == QStyleOptionMenuItem::Separator) { - w = 10; - SInt16 ash; - GetThemeMenuSeparatorHeight(&ash); - h = ash; - } else { - h = mi->fontMetrics.height() + 2; - if (!mi->icon.isNull()) { -#if QT_CONFIG(combobox) - if (comboBox) { - const QSize &iconSize = comboBox->iconSize(); - h = qMax(h, iconSize.height() + 4); - maxpmw = qMax(maxpmw, iconSize.width()); - } else -#endif - { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); - h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4); - } - } - } - if (mi->text.contains(QLatin1Char('\t'))) - w += 12; - if (mi->menuItemType == QStyleOptionMenuItem::SubMenu) - w += 20; - if (maxpmw) - w += maxpmw + 6; - // add space for a check. All items have place for a check too. - w += 20; -#if QT_CONFIG(combobox) - if (comboBox && comboBox->isVisible()) { - QStyleOptionComboBox cmb; - cmb.initFrom(comboBox); - cmb.editable = false; - cmb.subControls = QStyle::SC_ComboBoxEditField; - cmb.activeSubControls = QStyle::SC_None; - w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb, - QStyle::SC_ComboBoxEditField, - comboBox).width()); - } else -#endif - { - w += 12; - } - sz = QSize(w, h); - } - break; - case CT_MenuBarItem: - if (!sz.isEmpty()) - sz += QSize(12, 4); // Constants from QWindowsStyle - break; - case CT_ToolButton: - sz.rwidth() += 10; - sz.rheight() += 10; - return sz; - case CT_ComboBox: { - sz.rwidth() += 50; - const QStyleOptionComboBox *cb = qstyleoption_cast(opt); - if (cb && !cb->editable) - sz.rheight() += 2; - break; - } - case CT_Menu: { - if (proxy() == this) { - sz = csz; - } else { - QStyleHintReturnMask menuMask; - QStyleOption myOption = *opt; - myOption.rect.setSize(sz); - if (proxy()->styleHint(SH_Menu_Mask, &myOption, widget, &menuMask)) - sz = menuMask.region.boundingRect().size(); - } - break; } - case CT_HeaderSection:{ - const QStyleOptionHeader *header = qstyleoption_cast(opt); - sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); - if (header->text.contains(QLatin1Char('\n'))) - useAquaGuideline = false; - break; } - case CT_ScrollBar : - // Make sure that the scroll bar is large enough to display the thumb indicator. - if (const QStyleOptionSlider *slider = qstyleoption_cast(opt)) { - const int minimumSize = scrollButtonsCutoffSize(thumbIndicatorCutoff, widgetSizePolicy(widget, opt)); - if (slider->orientation == Qt::Horizontal) - sz = sz.expandedTo(QSize(minimumSize, sz.height())); - else - sz = sz.expandedTo(QSize(sz.width(), minimumSize)); - } - break; - case CT_ItemViewItem: - if (const QStyleOptionViewItem *vopt = qstyleoption_cast(opt)) { - sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget); - sz.setHeight(sz.height() + 2); - } - break; - - default: - sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); - } - - if (useAquaGuideline){ - QSize macsz; - if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QAquaSizeUnknown) { - if (macsz.width() != -1) - sz.setWidth(macsz.width()); - if (macsz.height() != -1) - sz.setHeight(macsz.height()); - } - } - - // The sizes that Carbon and the guidelines gives us excludes the focus frame. - // We compensate for this by adding some extra space here to make room for the frame when drawing: - if (const QStyleOptionComboBox *combo = qstyleoption_cast(opt)){ - QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget); - int bkind = 0; - switch (widgetSize) { - default: - case QAquaSizeLarge: - bkind = combo->editable ? kThemeComboBox : kThemePopupButton; - break; - case QAquaSizeSmall: - bkind = combo->editable ? int(kThemeComboBoxSmall) : int(kThemePopupButtonSmall); - break; - case QAquaSizeMini: - bkind = combo->editable ? kThemeComboBoxMini : kThemePopupButtonMini; - break; - } - HIRect tmpRect = {{0, 0}, {0, 0}}; - HIRect diffRect = QMacStylePrivate::comboboxInnerBounds(tmpRect, bkind); - sz.rwidth() -= qRound(diffRect.size.width); - sz.rheight() -= qRound(diffRect.size.height); - } else if (ct == CT_PushButton || ct == CT_ToolButton){ - ThemeButtonKind bkind; - QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget); - switch (ct) { - default: - case CT_PushButton: - if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { - if (btn->features & QStyleOptionButton::CommandLinkButton) { - return QCommonStyle::sizeFromContents(ct, opt, sz, widget); - } - } - - switch (widgetSize) { - default: - case QAquaSizeLarge: - bkind = kThemePushButton; - break; - case QAquaSizeSmall: - bkind = kThemePushButtonSmall; - break; - case QAquaSizeMini: - bkind = kThemePushButtonMini; - break; - } - break; - case CT_ToolButton: - switch (widgetSize) { - default: - case QAquaSizeLarge: - bkind = kThemeLargeBevelButton; - break; - case QAquaSizeMini: - case QAquaSizeSmall: - bkind = kThemeSmallBevelButton; - } - break; - } - - HIThemeButtonDrawInfo bdi; - bdi.version = qt_mac_hitheme_version; - bdi.state = kThemeStateActive; - bdi.kind = bkind; - bdi.value = kThemeButtonOff; - bdi.adornment = kThemeAdornmentNone; - HIRect macRect, myRect; - myRect = CGRectMake(0, 0, sz.width(), sz.height()); - HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect); - // Mini buttons only return their actual size in HIThemeGetButtonBackgroundBounds, so help them out a bit (guess), - if (bkind == kThemePushButtonMini) - macRect.size.height += 8.; - else if (bkind == kThemePushButtonSmall) - macRect.size.height -= 10; - sz.setWidth(sz.width() + int(macRect.size.width - myRect.size.width)); - sz.setHeight(sz.height() + int(macRect.size.height - myRect.size.height)); - } - return sz; -} - -void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal, - bool enabled, const QString &text, QPalette::ColorRole textRole) const -{ - if(flags & Qt::TextShowMnemonic) - flags |= Qt::TextHideMnemonic; - QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole); -} - -bool QMacStyle::event(QEvent *e) -{ - Q_D(QMacStyle); - if(e->type() == QEvent::FocusIn) { - QWidget *f = 0; - QWidget *focusWidget = QApplication::focusWidget(); -#if QT_CONFIG(graphicsview) - if (QGraphicsView *graphicsView = qobject_cast(focusWidget)) { - QGraphicsItem *focusItem = graphicsView->scene() ? graphicsView->scene()->focusItem() : 0; - if (focusItem && focusItem->type() == QGraphicsProxyWidget::Type) { - QGraphicsProxyWidget *proxy = static_cast(focusItem); - if (proxy->widget()) - focusWidget = proxy->widget()->focusWidget(); - } - } -#endif - if (focusWidget && focusWidget->testAttribute(Qt::WA_MacShowFocusRect)) { - f = focusWidget; - QWidget *top = f->parentWidget(); - while (top && !top->isWindow() && !(top->windowType() == Qt::SubWindow)) - top = top->parentWidget(); -#if QT_CONFIG(mainwindow) - if (qobject_cast(top)) { - QWidget *central = static_cast(top)->centralWidget(); - for (const QWidget *par = f; par; par = par->parentWidget()) { - if (par == central) { - top = central; - break; - } - if (par->isWindow()) - break; - } - } -#endif - } - if (f) { - if(!d->focusWidget) - d->focusWidget = new QFocusFrame(f); - d->focusWidget->setWidget(f); - } else if(d->focusWidget) { - d->focusWidget->setWidget(0); - } - } else if(e->type() == QEvent::FocusOut) { - if(d->focusWidget) - d->focusWidget->setWidget(0); - } - return false; -} - -QIcon QMacStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *opt, - const QWidget *widget) const -{ - switch (standardIcon) { - default: - return QCommonStyle::standardIcon(standardIcon, opt, widget); - case SP_ToolBarHorizontalExtensionButton: - case SP_ToolBarVerticalExtensionButton: { - QPixmap pixmap(QLatin1String(":/qt-project.org/styles/macstyle/images/toolbar-ext.png")); - if (standardIcon == SP_ToolBarVerticalExtensionButton) { - QPixmap pix2(pixmap.height(), pixmap.width()); - pix2.setDevicePixelRatio(pixmap.devicePixelRatio()); - pix2.fill(Qt::transparent); - QPainter p(&pix2); - p.translate(pix2.width(), 0); - p.rotate(90); - p.drawPixmap(0, 0, pixmap); - return pix2; - } - return pixmap; - } - } -} - -int QMacStyle::layoutSpacing(QSizePolicy::ControlType control1, - QSizePolicy::ControlType control2, - Qt::Orientation orientation, - const QStyleOption *option, - const QWidget *widget) const -{ - const int ButtonMask = QSizePolicy::ButtonBox | QSizePolicy::PushButton; - bool isMetal = (widget && widget->testAttribute(Qt::WA_MacBrushedMetal)); - int controlSize = getControlSize(option, widget); - - if (control2 == QSizePolicy::ButtonBox) { - /* - AHIG seems to prefer a 12-pixel margin between group - boxes and the row of buttons. The 20 pixel comes from - Builder. - */ - if (isMetal // (AHIG, guess, guess) - || (control1 & (QSizePolicy::Frame // guess - | QSizePolicy::GroupBox // (AHIG, guess, guess) - | QSizePolicy::TabWidget // guess - | ButtonMask))) { // AHIG - return_SIZE(14, 8, 8); - } else if (control1 == QSizePolicy::LineEdit) { - return_SIZE(8, 8, 8); // Interface Builder - } else { - return_SIZE(20, 7, 7); // Interface Builder - } - } - - if ((control1 | control2) & ButtonMask) { - if (control1 == QSizePolicy::LineEdit) - return_SIZE(8, 8, 8); // Interface Builder - else if (control2 == QSizePolicy::LineEdit) { - if (orientation == Qt::Vertical) - return_SIZE(20, 7, 7); // Interface Builder - else - return_SIZE(20, 8, 8); - } - return_SIZE(14, 8, 8); // Interface Builder - } - - switch (CT2(control1, control2)) { - case CT1(QSizePolicy::Label): // guess - case CT2(QSizePolicy::Label, QSizePolicy::DefaultType): // guess - case CT2(QSizePolicy::Label, QSizePolicy::CheckBox): // AHIG - case CT2(QSizePolicy::Label, QSizePolicy::ComboBox): // AHIG - case CT2(QSizePolicy::Label, QSizePolicy::LineEdit): // guess - case CT2(QSizePolicy::Label, QSizePolicy::RadioButton): // AHIG - case CT2(QSizePolicy::Label, QSizePolicy::Slider): // guess - case CT2(QSizePolicy::Label, QSizePolicy::SpinBox): // guess - case CT2(QSizePolicy::Label, QSizePolicy::ToolButton): // guess - return_SIZE(8, 6, 5); - case CT1(QSizePolicy::ToolButton): - return 8; // AHIG - case CT1(QSizePolicy::CheckBox): - case CT2(QSizePolicy::CheckBox, QSizePolicy::RadioButton): - case CT2(QSizePolicy::RadioButton, QSizePolicy::CheckBox): - if (orientation == Qt::Vertical) - return_SIZE(8, 8, 7); // AHIG and Builder - break; - case CT1(QSizePolicy::RadioButton): - if (orientation == Qt::Vertical) - return 5; // (Builder, guess, AHIG) - } - - if (orientation == Qt::Horizontal - && (control2 & (QSizePolicy::CheckBox | QSizePolicy::RadioButton))) - return_SIZE(12, 10, 8); // guess - - if ((control1 | control2) & (QSizePolicy::Frame - | QSizePolicy::GroupBox - | QSizePolicy::TabWidget)) { - /* - These values were chosen so that nested container widgets - look good side by side. Builder uses 8, which looks way - too small, and AHIG doesn't say anything. - */ - return_SIZE(16, 10, 10); // guess - } - - if ((control1 | control2) & (QSizePolicy::Line | QSizePolicy::Slider)) - return_SIZE(12, 10, 8); // AHIG - - if ((control1 | control2) & QSizePolicy::LineEdit) - return_SIZE(10, 8, 8); // AHIG - - /* - AHIG and Builder differ by up to 4 pixels for stacked editable - comboboxes. We use some values that work fairly well in all - cases. - */ - if ((control1 | control2) & QSizePolicy::ComboBox) - return_SIZE(10, 8, 7); // guess - - /* - Builder defaults to 8, 6, 5 in lots of cases, but most of the time the - result looks too cramped. - */ - return_SIZE(10, 8, 6); // guess -} - -/* -FontHash::FontHash() -{ - QHash::operator=(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFonts()); -} - -Q_GLOBAL_STATIC(FontHash, app_fonts) -FontHash *qt_app_fonts_hash() -{ - return app_fonts(); -} -*/ -QT_END_NAMESPACE From d0dffdfc012574da4a75241097b667d09bb39ba2 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 24 Aug 2017 09:30:14 +0200 Subject: [PATCH 127/146] Make sure the parent view will have focus when activation is given back When the focus is lost on an editor due to the application no longer being the active one then we have to ensure the parent view is going to get the focus when it is returned. Since the editor does not have focus when this check is done we need to manually account for this case by setting it on the parent view as if it would if the editor did have focus. Task-number: QTBUG-62253 Change-Id: I14ac347e9e3a2bfaa8715a45811b17c1c7cf15f8 Reviewed-by: Richard Moe Gustavsen --- .../itemviews/qabstractitemdelegate.cpp | 8 ++ .../tst_qabstractitemview.cpp | 79 +++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp index 3268fda2fca..117de8edf97 100644 --- a/src/widgets/itemviews/qabstractitemdelegate.cpp +++ b/src/widgets/itemviews/qabstractitemdelegate.cpp @@ -526,7 +526,15 @@ bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *ev if (tryFixup(editor)) emit q->commitData(editor); + // If the application loses focus while editing, then the focus needs to go back + // to the itemview when the editor closes. This ensures that when the application + // is active again it will have the focus on the itemview as expected. + const bool manuallyFixFocus = (event->type() == QEvent::FocusOut) && !editor->hasFocus() && + editor->parentWidget() && + (static_cast(event)->reason() == Qt::ActiveWindowFocusReason); emit q->closeEditor(editor, QAbstractItemDelegate::NoHint); + if (manuallyFixFocus) + editor->parentWidget()->setFocus(); } #ifndef QT_NO_SHORTCUT } else if (event->type() == QEvent::ShortcutOverride) { diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index e99ed8f2f42..47232212930 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -149,6 +149,8 @@ private slots: void inputMethodEnabled(); void currentFollowsIndexWidget_data(); void currentFollowsIndexWidget(); + void checkFocusAfterActivationChanges_data(); + void checkFocusAfterActivationChanges(); }; class MyAbstractItemDelegate : public QAbstractItemDelegate @@ -2443,5 +2445,82 @@ void tst_QAbstractItemView::currentFollowsIndexWidget() QCOMPARE(view->currentIndex(), item1->index()); } +class EditorItemDelegate : public QItemDelegate +{ +public: + EditorItemDelegate() : QItemDelegate(), openedEditor(nullptr) { } + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, + const QModelIndex &) const override + { + openedEditor = new QLineEdit(parent); + return openedEditor; + } + mutable QPointer openedEditor; +}; + +// Testing the case reported in QTBUG-62253. +// When an itemview with an editor that has focus loses focus +// due to a change in the active window then we need to check +// that the itemview gets focus once the activation is back +// on the original window. +void tst_QAbstractItemView::checkFocusAfterActivationChanges_data() +{ + QTest::addColumn("viewType"); + + QTest::newRow("QListView") << "QListView"; + QTest::newRow("QTableView") << "QTableView"; + QTest::newRow("QTreeView") << "QTreeView"; +} + +void tst_QAbstractItemView::checkFocusAfterActivationChanges() +{ + QFETCH(QString, viewType); + + const QRect availableGeo = qApp->primaryScreen()->availableGeometry(); + const int halfWidth = availableGeo.width() / 2; + QWidget otherTopLevel; + otherTopLevel.setGeometry(availableGeo.x(), availableGeo.y(), + halfWidth, availableGeo.height()); + otherTopLevel.show(); + + QWidget w; + w.setGeometry(availableGeo.x() + halfWidth, availableGeo.y(), + halfWidth, availableGeo.height()); + QLineEdit *le = new QLineEdit(&w); + QAbstractItemView *view = 0; + if (viewType == "QListView") + view = new QListView(&w); + else if (viewType == "QTableView") + view = new QTableView(&w); + else if (viewType == "QTreeView") + view = new QTreeView(&w); + + QStandardItemModel model(5, 5); + view->setModel(&model); + view->move(0, 50); + EditorItemDelegate delegate; + view->setItemDelegate(&delegate); + w.show(); + + QTest::qWaitForWindowActive(&w); + QVERIFY(le->hasFocus()); + + view->setFocus(); + QVERIFY(view->hasFocus()); + + view->edit(model.index(0,0)); + QVERIFY(QTest::qWaitForWindowExposed(delegate.openedEditor)); + QVERIFY(delegate.openedEditor->hasFocus()); + + QApplication::setActiveWindow(&otherTopLevel); + QTest::qWaitForWindowActive(&otherTopLevel); + otherTopLevel.setFocus(); + QVERIFY(!delegate.openedEditor); + + QApplication::setActiveWindow(&w); + QTest::qWaitForWindowActive(&w); + QVERIFY(view->hasFocus()); +} + QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc" From 2442328393c516406d19c5fdc4065daa90b78369 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 14 Feb 2018 14:22:26 +0100 Subject: [PATCH 128/146] Document use of Unicode Character Database [ChangeLog][Third-Party Code] Documented use of "Unicode Character Database (UCD)" in Qt Core. Change-Id: Id66877d04b4bbe6967d366bc631942e466a861ba Reviewed-by: Thiago Macieira --- .../{CLDR_LICENSE.txt => UNICODE_LICENSE.txt} | 2 +- src/corelib/tools/qt_attribution.json | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) rename src/corelib/tools/{CLDR_LICENSE.txt => UNICODE_LICENSE.txt} (96%) diff --git a/src/corelib/tools/CLDR_LICENSE.txt b/src/corelib/tools/UNICODE_LICENSE.txt similarity index 96% rename from src/corelib/tools/CLDR_LICENSE.txt rename to src/corelib/tools/UNICODE_LICENSE.txt index ad28161436d..1c73202b743 100644 --- a/src/corelib/tools/CLDR_LICENSE.txt +++ b/src/corelib/tools/UNICODE_LICENSE.txt @@ -1,4 +1,4 @@ -Copyright © 1991-2016 Unicode, Inc. All rights reserved. +Copyright © 1991-2018 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html. Permission is hereby granted, free of charge, to any person obtaining diff --git a/src/corelib/tools/qt_attribution.json b/src/corelib/tools/qt_attribution.json index eec2cd67959..f9c0d8991b3 100644 --- a/src/corelib/tools/qt_attribution.json +++ b/src/corelib/tools/qt_attribution.json @@ -1,3 +1,20 @@ +[ +{ + "Id": "unicode-character-database", + "Name": "Unicode Character Database (UCD)", + "QDocModule": "qtcore", + "QtUsage": "Qt Core uses data obtained from UCD files for working with characters and strings.", + "Files": "qunicodetables_p.h qunicodetables.cpp", + + "Description": "The Unicode Character Database (UCD) is a set of files that + define the Unicode character properties and internal mappings.", + "Homepage": "https://www.unicode.org/ucd/", + "Version": "10.0.0", + "License": "Unicode License Agreement - Data Files and Software (2016)", + "LicenseId": "Unicode-DFS-2016", + "LicenseFile": "UNICODE_LICENSE.txt", + "Copyright": "Copyright (C) 1991-2018 Unicode, Inc." +}, { "Id": "cldr-data", "Name": "Unicode CLDR (Unicode Common Locale Data Repository)", @@ -8,6 +25,7 @@ "Description": "QTimeZone includes data obtained from the CLDR data files.", "License": "Unicode Data Files and Software License", "LicenseId": "Unicode-TOU", - "LicenseFile": "CLDR_LICENSE.txt", + "LicenseFile": "UNICODE_LICENSE.txt", "Copyright": "Copyright (C) 1991-2016 Unicode, Inc." } +] From f93d732dd17e35757d8ba554dfbecc0d4dd89e25 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 14 Feb 2018 14:55:25 +0100 Subject: [PATCH 129/146] Update Unicode CLDR third party documentation [ChangeLog][Third-Party Code] Clarified use of "Unicode Common Local Data Repository (CLDR)" in the documentation. Also updated SPDX license name / ID. Change-Id: I7261c675251dcca118f2661061a09b9c9200486e Reviewed-by: Lars Knoll --- src/corelib/tools/qt_attribution.json | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/corelib/tools/qt_attribution.json b/src/corelib/tools/qt_attribution.json index f9c0d8991b3..49a76cb8b48 100644 --- a/src/corelib/tools/qt_attribution.json +++ b/src/corelib/tools/qt_attribution.json @@ -16,16 +16,20 @@ "Copyright": "Copyright (C) 1991-2018 Unicode, Inc." }, { - "Id": "cldr-data", - "Name": "Unicode CLDR (Unicode Common Locale Data Repository)", + "Id": "unicode-cldr", + "Name": "Unicode Common Locale Data Repository (CLDR)", "QDocModule": "qtcore", - "QtUsage": "Used in Qt Core (QTimeZone). Disable the timezone feature to avoid.", - "Files": "qlocale_data_p.h", + "QtUsage": "Used in Qt Core (QTimeZone, QLocale).", + "Files": "qlocale_data_p.h qtimezoneprivate_data_p.h", - "Description": "QTimeZone includes data obtained from the CLDR data files.", - "License": "Unicode Data Files and Software License", - "LicenseId": "Unicode-TOU", + "Description": "The Unicode CLDR provides key building blocks for software to support the + world's languages, with the largest and most extensive standard repository of locale data + available.", + "Homepage": "http://cldr.unicode.org/", + "Version": "v31.0.1", + "License": "Unicode License Agreement - Data Files and Software (2016)", + "LicenseId": "Unicode-DFS-2016", "LicenseFile": "UNICODE_LICENSE.txt", - "Copyright": "Copyright (C) 1991-2016 Unicode, Inc." + "Copyright": "Copyright (C) 1991-2017 Unicode, Inc." } ] From 2908a13a789c9217be312e51066df326028a418d Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 7 Feb 2018 12:24:53 +0100 Subject: [PATCH 130/146] Doc: Remove Validators example from highlighted widgets examples Contains several bugs. Task-number: QTBUG-60635 Change-Id: I64d7431ebab2e3f7776e7d2a94e301d677c1bb1e Reviewed-by: Frederik Gladhorn --- examples/widgets/doc/src/validators.qdoc | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/widgets/doc/src/validators.qdoc b/examples/widgets/doc/src/validators.qdoc index bbb2e5f7b6b..9d82f3f5750 100644 --- a/examples/widgets/doc/src/validators.qdoc +++ b/examples/widgets/doc/src/validators.qdoc @@ -28,7 +28,6 @@ /*! \example widgets/validators \title Validators Example - \ingroup examples-widgets \brief The Validators example shows the signal emission behavior of input validators. From b59181c42d61fb756c87978642ea5457a91051fb Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Thu, 15 Feb 2018 13:50:53 +0200 Subject: [PATCH 131/146] Blacklist tst_QMdiSubWindow::setOpaqueResizeAndMove on macOS 10.12 Several recent failures. Task-number: QTBUG-66433 Task-number: QTBUG-66216 Change-Id: I69e535579c886cc725f66d584af7f8821bee70da Reviewed-by: Sami Nurmenniemi Reviewed-by: Friedemann Kleint --- tests/auto/widgets/widgets/qmdisubwindow/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/widgets/widgets/qmdisubwindow/BLACKLIST diff --git a/tests/auto/widgets/widgets/qmdisubwindow/BLACKLIST b/tests/auto/widgets/widgets/qmdisubwindow/BLACKLIST new file mode 100644 index 00000000000..26d1776b0d4 --- /dev/null +++ b/tests/auto/widgets/widgets/qmdisubwindow/BLACKLIST @@ -0,0 +1,2 @@ +[setOpaqueResizeAndMove] +osx-10.12 From 2a80c04d3bbc45b5d1293a5141839c0b4719f772 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 15 Feb 2018 11:02:07 +0100 Subject: [PATCH 132/146] Fix crash when reading window titles with XCB This is a regression introduced with commit cb142954c54b7a6e391950d9209b5cea9252092b that changed the code from using QString:fromUtf8(name, propertyLength) to QString::fromUtf8(name), assuming that the property name is a zero-terminated string. That however is not correct. ASAN trace: ==4039==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400001e0b4 at pc 0x7f3383c7d66e bp 0x7ffdc8e3d9b0 sp 0x7ffdc8e3d158 READ of size 5 at 0x60400001e0b4 thread T0 #0 0x7f3383c7d66d (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5166d) #1 0x7f337602f32a in QString::fromUtf8(char const*, int) ../../../../include/QtCore/../../src/corelib/tools/qstring.h:569 #2 0x7f337602f32a in QXcbWindow::windowTitle(QXcbConnection const*, unsigned int) /home/simon/dev/qt-5.11/qtbase/src/plugins/platforms/xcb/qxcbwindow.cpp:2861 [...] 0x60400001e0b4 is located 0 bytes to the right of 36-byte region [0x60400001e090,0x60400001e0b4) allocated by thread T1 (QXcbEventReader) here: #0 0x7f3383d0ab50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50) #1 0x7f337b397e2b (/usr/lib/x86_64-linux-gnu/libxcb.so.1+0xde2b) Change-Id: Ia5024602d3aacb924b5dcd3956672da2a8f10feb Reviewed-by: Friedemann Kleint --- src/plugins/platforms/xcb/qxcbwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 61cfed4db78..e9a6e536a75 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2857,7 +2857,7 @@ QString QXcbWindow::windowTitle(const QXcbConnection *conn, xcb_window_t window) utf8Atom, 0, 1024); if (reply && reply->format == 8 && reply->type == utf8Atom) { const char *name = reinterpret_cast(xcb_get_property_value(reply.get())); - return QString::fromUtf8(name); + return QString::fromUtf8(name, xcb_get_property_value_length(reply.get())); } return QString(); } From ea21b36836abd6c2bb6d139c9d4b8149acdc4785 Mon Sep 17 00:00:00 2001 From: Yulong Bai Date: Tue, 13 Feb 2018 16:33:32 +0100 Subject: [PATCH 133/146] QFusionStyle: fix the checkbox rendering in low DPI settings Fixed some regression of checkbox's size brought in by c9f68a5. Using qreal and QRectF to avoid the round error accumulation of sizes in low dpi situations. Tweaked the look of the check mark. Task-number: QTBUG-66343 Change-Id: I8f68144f60437907701021bb43ee736dfcb7241f Reviewed-by: Richard Moe Gustavsen --- src/widgets/styles/qfusionstyle.cpp | 35 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 554c45d5708..6873ca876e6 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -763,7 +763,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->drawRect(rect); QColor checkMarkColor = option->palette.text().color().darker(120); - const int checkMarkPadding = 1 + rect.width() * 0.2; // at least one pixel padding + const qreal checkMarkPadding = 1 + rect.width() * 0.13; // at least one pixel padding if (checkbox->state & State_NoChange) { gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft()); @@ -775,20 +775,23 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->setPen(QPen(checkMarkColor, 1)); painter->setBrush(gradient); painter->drawRect(rect.adjusted(checkMarkPadding, checkMarkPadding, -checkMarkPadding, -checkMarkPadding)); + } else if (checkbox->state & State_On) { - qreal penWidth = QStyleHelper::dpiScaled(1.8); - penWidth = qMax(penWidth , 0.18 * rect.height()); - penWidth = qMin(penWidth , 0.30 * rect.height()); + qreal penWidth = QStyleHelper::dpiScaled(1.5); + penWidth = qMax(penWidth , 0.13 * rect.height()); + penWidth = qMin(penWidth , 0.20 * rect.height()); + QPen checkPen = QPen(checkMarkColor, penWidth); checkMarkColor.setAlpha(210); - painter->setPen(QPen(checkMarkColor, penWidth)); + painter->translate(dpiScaled(-0.8), dpiScaled(0.5)); + painter->setPen(checkPen); painter->setBrush(Qt::NoBrush); - painter->translate(-0.8, 0.5); // Draw checkmark QPainterPath path; - path.moveTo(1.33 * checkMarkPadding, rect.height() / 2.0); - path.lineTo(rect.width() / 2.0, rect.height() - checkMarkPadding); - path.lineTo(rect.width() - checkMarkPadding * 0.92, checkMarkPadding); + const qreal rectHeight = rect.height(); // assuming height equals width + path.moveTo(checkMarkPadding + rectHeight * 0.11, rectHeight * 0.47); + path.lineTo(rectHeight * 0.5, rectHeight - checkMarkPadding); + path.lineTo(rectHeight - checkMarkPadding, checkMarkPadding); painter->drawPath(path.translated(rect.topLeft())); } } @@ -1559,8 +1562,8 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio bool ignoreCheckMark = false; const int checkColHOffset = windowsItemHMargin + windowsItemFrame - 1; - int checkcol = qMax(menuItem->rect.height() * 0.7, - qMax(menuItem->maxIconWidth * 1.0, dpiScaled(17))); // icon checkbox's highlihgt column width + int checkcol = qMax(menuItem->rect.height() * 0.79, + qMax(menuItem->maxIconWidth * 1.0, dpiScaled(21))); // icon checkbox's highlihgt column width if ( #if QT_CONFIG(combobox) qobject_cast(widget) || @@ -1569,10 +1572,12 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio ignoreCheckMark = true; //ignore the checkmarks provided by the QComboMenuDelegate if (!ignoreCheckMark) { - // Check - const int boxMargin = dpiScaled(4); - const int boxWidth = checkcol - 2 * boxMargin; - QRect checkRect(option->rect.left() + boxMargin + checkColHOffset, option->rect.center().y() - boxWidth/2 + 1, boxWidth, boxWidth); + // Check, using qreal and QRectF to avoid error accumulation + const qreal boxMargin = dpiScaled(3.5); + const qreal boxWidth = checkcol - 2 * boxMargin; + QRectF checkRectF(option->rect.left() + boxMargin + checkColHOffset, option->rect.center().y() - boxWidth/2 + 1, boxWidth, boxWidth); + QRect checkRect = checkRectF.toRect(); + checkRect.setWidth(checkRect.height()); // avoid .toRect() round error results in non-perfect square checkRect = visualRect(menuItem->direction, menuItem->rect, checkRect); if (checkable) { if (menuItem->checkType & QStyleOptionMenuItem::Exclusive) { From 6c4f5ecef0c9bc8bfb31ef4099d53ba02f0611aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 13 Feb 2018 17:11:50 +0100 Subject: [PATCH 134/146] Share event dispatcher creation between QThreadPrivate and QCoreApplication A step towards having the application do its event dispatching though the thread data's dispatcher, like QEventLoop, instead of keeping two references to the same dispatcher, one in QCoreApplicationPrivate and one in QThreadData. Change-Id: I7b215e7e99869d25638ec67f0666f632a508cc0f Reviewed-by: Thiago Macieira --- src/corelib/kernel/qcoreapplication.cpp | 27 ++++--------------------- src/corelib/thread/qthread_unix.cpp | 3 ++- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index ef431baca63..4e32f909643 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -538,29 +538,10 @@ void QCoreApplicationPrivate::cleanupThreadData() void QCoreApplicationPrivate::createEventDispatcher() { Q_Q(QCoreApplication); -#if defined(Q_OS_UNIX) -# if defined(Q_OS_DARWIN) - bool ok = false; - int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok); - if (ok && value > 0) - eventDispatcher = new QEventDispatcherCoreFoundation(q); - else - eventDispatcher = new QEventDispatcherUNIX(q); -# elif !defined(QT_NO_GLIB) - if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && QEventDispatcherGlib::versionSupported()) - eventDispatcher = new QEventDispatcherGlib(q); - else - eventDispatcher = new QEventDispatcherUNIX(q); -# else - eventDispatcher = new QEventDispatcherUNIX(q); -# endif -#elif defined(Q_OS_WINRT) - eventDispatcher = new QEventDispatcherWinRT(q); -#elif defined(Q_OS_WIN) - eventDispatcher = new QEventDispatcherWin32(q); -#else -# error "QEventDispatcher not yet ported to this platform" -#endif + QThreadData *data = QThreadData::current(); + Q_ASSERT(!data->hasEventDispatcher()); + eventDispatcher = QThreadPrivate::createEventDispatcher(data); + eventDispatcher->setParent(q); } void QCoreApplicationPrivate::eventDispatcherReady() diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 2c815b870a2..6248842d78d 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -296,8 +296,9 @@ QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *dat else return new QEventDispatcherUNIX; #elif !defined(QT_NO_GLIB) + const bool isQtMainThread = data->thread == QCoreApplicationPrivate::mainThread(); if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") - && qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB") + && (isQtMainThread || qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB")) && QEventDispatcherGlib::versionSupported()) return new QEventDispatcherGlib; else From 5f96432ea968c4157539c7e4641303431d06252e Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Thu, 8 Feb 2018 10:17:44 +0100 Subject: [PATCH 135/146] eglfs_kms_vsp2: Recover if queuing input buffers fails Clear all queued buffers, and reinitialize the Qt layer so we can try again next time. Change-Id: I921f6f457666206be92aadf2fe40b855e6ebff62 Reviewed-by: Laszlo Agocs --- .../eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp | 18 ++++++++--- .../eglfs_kms_vsp2/qeglfskmsvsp2screen.h | 1 + .../eglfs_kms_vsp2/qvsp2blendingdevice.cpp | 30 ++++++++++++++++--- .../eglfs_kms_vsp2/qvsp2blendingdevice.h | 1 + 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp index 88b401c920b..475d9d55dd1 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.cpp @@ -141,10 +141,15 @@ void QEglFSKmsVsp2Screen::initDumbFrameBuffers() void QEglFSKmsVsp2Screen::initVsp2() { qCDebug(qLcEglfsKmsDebug, "Initializing Vsp2 hardware"); - const QSize screenSize = rawGeometry().size(); - m_blendDevice.reset(new QVsp2BlendingDevice(screenSize)); + m_blendDevice.reset(new QVsp2BlendingDevice(rawGeometry().size())); // Enable input for main buffer drawn by the compositor (always on) + initQtLayer(); +} + +void QEglFSKmsVsp2Screen::initQtLayer() +{ + const QSize screenSize = rawGeometry().size(); const uint bytesPerLine = uint(screenSize.width()) * 4; //TODO: is this ok? bool formatSet = m_blendDevice->enableInput(m_qtLayer, QRect(QPoint(), screenSize), m_output.drm_format, bytesPerLine); if (!formatSet) { @@ -298,8 +303,13 @@ void QEglFSKmsVsp2Screen::blendAndFlipDrm() vBlank.request.signal = 0; drmWaitVBlank(driFd, &vBlank); - if (!m_blendDevice->blend(backBuffer.dmabufFd)) - qWarning() << "Vsp2: blending failed"; + if (!m_blendDevice->blend(backBuffer.dmabufFd)) { + qWarning() << "Vsp2: Blending failed"; + + // For some reason, a failed blend may often mess up the qt layer, so reinitialize it here + m_blendDevice->disableInput(m_qtLayer); + initQtLayer(); + } for (auto cb : m_blendFinishedCallbacks) cb(); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h index fa03e367853..76185103338 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2screen.h @@ -60,6 +60,7 @@ public: void initDumbFrameBuffers(); void initVsp2(); + void initQtLayer(); //TODO: use a fixed index API instead of auto increment? int addLayer(int dmabufFd, const QSize &size, const QPoint &position, uint drmPixelFormat, uint bytesPerLine); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp index 879d312341f..132806a2e3b 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.cpp @@ -219,11 +219,12 @@ bool QVsp2BlendingDevice::blend(int outputDmabufFd) if (!m_dirty) qWarning("Blending without being dirty, should not be necessary"); - if (!m_inputs[0].enabled) { - qWarning("Vsp2: Can't blend with layer 0 disabled"); + if (!hasContinuousLayers()) { + qWarning("Vsp2: Can't blend when layers are not enabled in order from 0 without gaps."); return false; } + bool queueingFailed = false; // Queue dma input buffers for (int i=0; i < m_inputs.size(); ++i) { auto &input = m_inputs[i]; @@ -233,12 +234,22 @@ bool QVsp2BlendingDevice::blend(int outputDmabufFd) << "with dmabuf" << input.dmabuf.fd << "and size" << input.geometry.size(); - if (!disableInput(i)) - qWarning() << "Vsp2: Failed to disable input" << i; + queueingFailed = true; } } } + if (queueingFailed) { + qWarning() << "Vsp2: Trying to clean up queued buffers"; + for (auto &input : qAsConst(m_inputs)) { + if (input.enabled) { + if (!input.rpfInput->clearBuffers()) + qWarning() << "Vsp2: Failed to remove buffers after an aborted blend"; + } + } + return false; + } + if (!m_wpfOutput->queueBuffer(outputDmabufFd, m_screenSize)) { qWarning() << "Vsp2: Failed to queue blending output buffer" << outputDmabufFd << m_screenSize; return false; @@ -270,6 +281,17 @@ int QVsp2BlendingDevice::numInputs() const return m_inputs.size(); } +bool QVsp2BlendingDevice::hasContinuousLayers() const +{ + bool seenDisabled = false; + for (auto &input : qAsConst(m_inputs)) { + if (seenDisabled && input.enabled) + return false; + seenDisabled |= !input.enabled; + } + return m_inputs[0].enabled; +} + bool QVsp2BlendingDevice::streamOn() { for (auto &input : m_inputs) { diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h index be48954f47b..ee34ae654ae 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qvsp2blendingdevice.h @@ -63,6 +63,7 @@ public: bool blend(int outputDmabufFd); int numInputs() const; bool isDirty() const { return m_dirty; } + bool hasContinuousLayers() const; private: bool streamOn(); bool streamOff(); From dc334b60d9b187edf2ab579c535a6d5358eeb414 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 15 Feb 2018 15:56:11 +0100 Subject: [PATCH 136/146] Update documented sqlite version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Augments 3d355015917ff2991b7d01deed2a1abfa15020b7 Change-Id: I074f966206bcfd1b2b7b55bb2ed910219bb7726d Reviewed-by: Mårten Nordheim Reviewed-by: Andy Shaw --- src/3rdparty/sqlite/qt_attribution.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rdparty/sqlite/qt_attribution.json b/src/3rdparty/sqlite/qt_attribution.json index 50c179bf6ef..38004772390 100644 --- a/src/3rdparty/sqlite/qt_attribution.json +++ b/src/3rdparty/sqlite/qt_attribution.json @@ -6,7 +6,7 @@ "Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.", "Homepage": "http://www.sqlite.org/", - "Version": "3.20.1", + "Version": "3.22.0", "License": "Public Domain", "Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed." } From 5e98873cd3408d3900903efd926c36158941d67e Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 7 Feb 2018 18:37:22 +0100 Subject: [PATCH 137/146] Fix of flaky qFutureAssignmentLeak test Switch to QTRY_COMPARE since thread-local references might be held shortly after finished is signalled. Change-Id: Ia32f1f45f6cc461352558e0f2acf9612f8a4639e Reviewed-by: Thiago Macieira --- tests/auto/concurrent/qtconcurrentmap/BLACKLIST | 3 --- .../concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp | 7 +++++-- 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 tests/auto/concurrent/qtconcurrentmap/BLACKLIST diff --git a/tests/auto/concurrent/qtconcurrentmap/BLACKLIST b/tests/auto/concurrent/qtconcurrentmap/BLACKLIST deleted file mode 100644 index 0320f61fab0..00000000000 --- a/tests/auto/concurrent/qtconcurrentmap/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -[qFutureAssignmentLeak] -ci opensuse -ci ubuntu-16.04 diff --git a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp index 2d7c0c2f642..f539f012dff 100644 --- a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp +++ b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp @@ -2402,9 +2402,12 @@ void tst_QtConcurrentMap::qFutureAssignmentLeak() future.waitForFinished(); } - QCOMPARE(currentInstanceCount.load(), 1000); + // Use QTRY_COMPARE because QtConcurrent::ThreadEngine::asynchronousFinish() + // deletes its internals after signaling finished, so it might still be holding + // on to copies of InstanceCounter for a short while. + QTRY_COMPARE(currentInstanceCount.load(), 1000); future = QFuture(); - QCOMPARE(currentInstanceCount.load(), 0); + QTRY_COMPARE(currentInstanceCount.load(), 0); } inline void increment(int &num) From 65b004204e3bccee2071761dc73206e0a15bce8c Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Feb 2018 16:20:05 +0100 Subject: [PATCH 138/146] syncqt: prune dead $quoted_basedir variable amends f5a5272bc7a. Change-Id: I6bec21cb87f5e69d659836bc2b2a1e68af70a75c Reviewed-by: Lars Knoll Reviewed-by: Thiago Macieira --- bin/syncqt.pl | 3 --- 1 file changed, 3 deletions(-) diff --git a/bin/syncqt.pl b/bin/syncqt.pl index 02e55d847eb..dd38bece76d 100755 --- a/bin/syncqt.pl +++ b/bin/syncqt.pl @@ -77,7 +77,6 @@ sub normalizePath { our $out_basedir = getcwd(); normalizePath(\$out_basedir); our $basedir; -our $quoted_basedir; # Make sure we use Windows line endings for chomp and friends on Windows. $INPUT_RECORD_SEPARATOR = "\r\n" if ($^O eq "msys"); @@ -728,7 +727,6 @@ $basedir = locateSyncProfile($out_basedir); if ($basedir) { $basedir = dirname($basedir) ; normalizePath(\$basedir); - $quoted_basedir = "\Q$basedir"; } # -------------------------------------------------------------------- @@ -796,7 +794,6 @@ while ( @ARGV ) { die "Could not find a sync.profile for '$arg'\n" if (!$basedir); $basedir = dirname($basedir); normalizePath(\$basedir); - $quoted_basedir = "\Q$basedir"; $var = "ignore"; } From a060bf9673477499d85b04d8d5b21fb2a2f15c4f Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Feb 2018 17:39:58 +0100 Subject: [PATCH 139/146] syncqt: untangle loadSyncProfile() calling convention don't pass arguments, as the sourced sync.profile's make assumptions about the global variables' presence anyway. don't return a value, as it's ignored anyway. fix the documentation (also that of locateSyncProfile()). Change-Id: I7527546718b12737d7a4551a834d7f0ca26a8a7e Reviewed-by: Lars Knoll Reviewed-by: Thiago Macieira --- bin/syncqt.pl | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/bin/syncqt.pl b/bin/syncqt.pl index dd38bece76d..52bd97e88d0 100755 --- a/bin/syncqt.pl +++ b/bin/syncqt.pl @@ -647,17 +647,15 @@ sub listSubdirs { ###################################################################### # Syntax: loadSyncProfile() # -# Purpose: Locates the sync.profile. -# Returns: Hashmap of module name -> directory. +# Purpose: Loads the sync.profile. ###################################################################### sub loadSyncProfile { - my ($srcbase, $outbase) = @_; if ($verbose_level) { - print(" = $$srcbase \n"); - print(" = $$outbase \n"); + print(" = $basedir \n"); + print(" = $out_basedir \n"); } - my $syncprofile = "$$srcbase/sync.profile"; + my $syncprofile = "$basedir/sync.profile"; my $result; unless ($result = do "$syncprofile") { die "syncqt couldn't parse $syncprofile: $@" if $@; @@ -669,8 +667,6 @@ sub loadSyncProfile { $reverse_classnames{$cn} = $fn; } } - - return $result; } sub basePrettify { @@ -685,6 +681,11 @@ sub cleanPath { return $arg; } +###################################################################### +# Syntax: locateSyncProfile() +# +# Purpose: Locates the sync.profile. +###################################################################### sub locateSyncProfile { my ($directory) = @_; @@ -889,7 +890,7 @@ our @ignore_for_qt_module_check = (); our %inject_headers = (); # load the module's sync.profile here, before we can -loadSyncProfile(\$basedir, \$out_basedir); +loadSyncProfile(); @modules_to_sync = keys(%modules) if($#modules_to_sync == -1); From ede6c447560b9419ee9d2991059e488a7d5a3208 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Feb 2018 17:56:32 +0100 Subject: [PATCH 140/146] syncqt: fix injected headers outside qtbase in non-prefix builds in non-prefix configs, one has to differentiate between the module's own build dir and qtbase's build dir, because the forwarding headers are placed in -outdir under include/, while the actual headers end up in the real build dir under src/. Change-Id: I1d8ac904556b354bd113995316ba11dd6560a70d Reviewed-by: Lars Knoll Reviewed-by: Thiago Macieira --- bin/syncqt.pl | 23 ++++++++++++++++++++--- mkspecs/features/qt_module_headers.prf | 3 ++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/bin/syncqt.pl b/bin/syncqt.pl index 52bd97e88d0..02194aa0b75 100755 --- a/bin/syncqt.pl +++ b/bin/syncqt.pl @@ -76,6 +76,7 @@ sub normalizePath { # set output basedir to be where ever syncqt is run from our $out_basedir = getcwd(); normalizePath(\$out_basedir); +our $build_basedir = $out_basedir; our $basedir; # Make sure we use Windows line endings for chomp and friends on Windows. @@ -128,6 +129,7 @@ sub showUsage print " -showonly Show action but not perform (default: " . ($showonly ? "yes" : "no") . ")\n"; print " -minimal Do not create CamelCase headers (default: " . ($minimal ? "yes" : "no") . ")\n"; print " -outdir Specify output directory for sync (default: $out_basedir)\n"; + print " -builddir Specify build directory for sync (default: $build_basedir)\n"; print " -version Specify the module's version (default: detect from qglobal.h)\n"; print " -quiet Only report problems, not activity (same as -verbose 0)\n"; print " -v, -verbose Sets the verbosity level (max. 4) (default: $verbose_level)\n"; @@ -652,6 +654,7 @@ sub listSubdirs { sub loadSyncProfile { if ($verbose_level) { print(" = $basedir \n"); + print(" = $build_basedir \n"); print(" = $out_basedir \n"); } @@ -672,6 +675,7 @@ sub loadSyncProfile { sub basePrettify { my ($arg) = @_; $$arg =~ s,^\Q$basedir\E,,; + $$arg =~ s,^\Q$build_basedir\E,,; $$arg =~ s,^\Q$out_basedir\E,,; } @@ -724,7 +728,7 @@ sub globosort($$) { } # check if this is an in-source build, and if so use that as the basedir too -$basedir = locateSyncProfile($out_basedir); +$basedir = locateSyncProfile($build_basedir); if ($basedir) { $basedir = dirname($basedir) ; normalizePath(\$basedir); @@ -749,6 +753,9 @@ while ( @ARGV ) { } elsif($arg eq "-o" || $arg eq "-outdir") { $var = "output"; $val = shift @ARGV; + } elsif($arg eq "-builddir") { + $var = "build"; + $val = shift @ARGV; } elsif($arg eq "-showonly" || $arg eq "-remove-stale" || $arg eq "-windows" || $arg eq "-relative" || $arg eq "-check-includes") { $var = substr($arg, 1); @@ -875,6 +882,16 @@ while ( @ARGV ) { $out_basedir = $outdir; } normalizePath(\$out_basedir); + } elsif ($var eq "build") { + my $outdir = $val; + if (checkRelative($outdir)) { + $build_basedir = getcwd(); + chomp $build_basedir; + $build_basedir .= "/" . $outdir; + } else { + $build_basedir = $outdir; + } + normalizePath(\$build_basedir); } } @@ -939,7 +956,7 @@ foreach my $lib (@modules_to_sync) { for my $p (keys %inject_headers) { next unless ($p =~ /^\Q$dir\E(\/|$)/); my $sp = $p; - $sp =~ s,^\Q$basedir\E/,$out_basedir/,; + $sp =~ s,^\Q$basedir\E/,$build_basedir/,; for my $n (@{$inject_headers{$p}}) { $injections{$sp."/".$n} = 1; } @@ -1037,7 +1054,7 @@ foreach my $lib (@modules_to_sync) { my $requires; my $iheader_src = $subdir . "/" . $header; my $iheader = $iheader_src; - $iheader =~ s/^\Q$basedir\E/$out_basedir/ if ($shadow); + $iheader =~ s/^\Q$basedir\E/$build_basedir/ if ($shadow); if ($check_includes) { # We need both $public_header and $private_header because QPA headers count as neither my $private_header = !$public_header && !$qpa_header diff --git a/mkspecs/features/qt_module_headers.prf b/mkspecs/features/qt_module_headers.prf index 931a26f5ae6..62b88c6fe2f 100644 --- a/mkspecs/features/qt_module_headers.prf +++ b/mkspecs/features/qt_module_headers.prf @@ -22,7 +22,8 @@ load(qt_build_paths) for(mod, MODULE_INCNAME): \ QMAKE_SYNCQT += -module $$mod QMAKE_SYNCQT += \ - -version $$VERSION -outdir $$system_quote($$MODULE_BASE_OUTDIR) $$MODULE_SYNCQT_DIR + -version $$VERSION -outdir $$system_quote($$MODULE_BASE_OUTDIR) \ + -builddir $$system_quote($$shadowed($$MODULE_BASE_INDIR)) $$MODULE_SYNCQT_DIR !silent: message($$QMAKE_SYNCQT) system($$QMAKE_SYNCQT)|error("Failed to run: $$QMAKE_SYNCQT") From 23eab78f510a9cfb050980f522dc23409e23fbdb Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Mon, 12 Feb 2018 22:44:32 +0100 Subject: [PATCH 141/146] QToolBar: Fix QToolbar extension button icon after LayoutDirectionChange When the layout direction is changed after the QToolButton is created, the extension button icon was not updated. Task-number: QTBUG-66344 Change-Id: I8690b2c42c4f485a39490f16b15b8ee58e6f4ace Reviewed-by: Friedemann Kleint --- src/widgets/widgets/qtoolbarextension.cpp | 20 +++++++++++++++++--- src/widgets/widgets/qtoolbarextension_p.h | 6 ++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/widgets/widgets/qtoolbarextension.cpp b/src/widgets/widgets/qtoolbarextension.cpp index 47cf16e0cc7..bbe7eddaa49 100644 --- a/src/widgets/widgets/qtoolbarextension.cpp +++ b/src/widgets/widgets/qtoolbarextension.cpp @@ -38,7 +38,7 @@ ****************************************************************************/ #include "qtoolbarextension_p.h" -#include +#include #include #include #include @@ -47,10 +47,11 @@ QT_BEGIN_NAMESPACE QToolBarExtension::QToolBarExtension(QWidget *parent) : QToolButton(parent) + , m_orientation(Qt::Horizontal) { setObjectName(QLatin1String("qt_toolbar_ext_button")); setAutoRaise(true); - setOrientation(Qt::Horizontal); + setOrientation(m_orientation); setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); setCheckable(true); } @@ -63,7 +64,8 @@ void QToolBarExtension::setOrientation(Qt::Orientation o) setIcon(style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton, &opt)); } else { setIcon(style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton, &opt)); - } + } + m_orientation = o; } void QToolBarExtension::paintEvent(QPaintEvent *) @@ -83,6 +85,18 @@ QSize QToolBarExtension::sizeHint() const return QSize(ext, ext); } +bool QToolBarExtension::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::LayoutDirectionChange: + setOrientation(m_orientation); + break; + default: + break; + } + return QToolButton::event(event); +} + QT_END_NAMESPACE #include "moc_qtoolbarextension_p.cpp" diff --git a/src/widgets/widgets/qtoolbarextension_p.h b/src/widgets/widgets/qtoolbarextension_p.h index a388f1e40f0..146e0e58c14 100644 --- a/src/widgets/widgets/qtoolbarextension_p.h +++ b/src/widgets/widgets/qtoolbarextension_p.h @@ -69,6 +69,12 @@ public: public Q_SLOTS: void setOrientation(Qt::Orientation o); + +protected: + bool event(QEvent *e) override; + +private: + Qt::Orientation m_orientation; }; QT_END_NAMESPACE From ad648ff293e1f1596f9d65205040c0f033b383ef Mon Sep 17 00:00:00 2001 From: Alexander Shevchenko Date: Thu, 15 Feb 2018 12:22:59 +0200 Subject: [PATCH 142/146] fix missing __builtin_mul_overflow for Windows ICC Complete 43c44d05ca6af4ec78c1dea84635375a637ff80d to cover builds using Windows ICC. Change-Id: I5f4d62f17b54835a58f3002744574c514cce5e39 Reviewed-by: Thiago Macieira --- src/corelib/global/qnumeric_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h index 9b86a165168..5f8a124bcc2 100644 --- a/src/corelib/global/qnumeric_p.h +++ b/src/corelib/global/qnumeric_p.h @@ -168,7 +168,7 @@ namespace { // size_t. Implementations for 8- and 16-bit types will work but may not be as // efficient. Implementations for 64-bit may be missing on 32-bit platforms. -#if (defined(Q_CC_GNU) && (Q_CC_GNU >= 500) || defined(Q_CC_INTEL)) || QT_HAS_BUILTIN(__builtin_add_overflowx) +#if (defined(Q_CC_GNU) && (Q_CC_GNU >= 500) || (defined(Q_CC_INTEL) && !defined(Q_OS_WIN))) || QT_HAS_BUILTIN(__builtin_add_overflowx) // GCC 5, ICC 18, and Clang 3.8 have builtins to detect overflows template inline From e8531501a70cd7805498d7009290905751cef0df Mon Sep 17 00:00:00 2001 From: Alexander Shevchenko Date: Thu, 15 Feb 2018 20:47:36 +0200 Subject: [PATCH 143/146] qsettings: add Advapi32 lib to Windows ICC builds Fix 'unresolved external symbol __imp_Reg*' errors for builds using Windows ICC. Change-Id: I99cb6d53c45cadb31b5675182753f168a7bf4ea3 Reviewed-by: Thiago Macieira --- tests/auto/corelib/io/qsettings/qsettings.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/corelib/io/qsettings/qsettings.pro b/tests/auto/corelib/io/qsettings/qsettings.pro index 7da73a549a1..5b4cc8a6916 100644 --- a/tests/auto/corelib/io/qsettings/qsettings.pro +++ b/tests/auto/corelib/io/qsettings/qsettings.pro @@ -5,5 +5,5 @@ SOURCES = tst_qsettings.cpp RESOURCES += qsettings.qrc INCLUDEPATH += $$PWD/../../kernel/qmetatype -win32-msvc*:LIBS += advapi32.lib +msvc: LIBS += advapi32.lib DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 From c7c20ce5e2fd8d784f50fbb44f689e50e89a4687 Mon Sep 17 00:00:00 2001 From: Alexander Shevchenko Date: Thu, 15 Feb 2018 21:23:48 +0200 Subject: [PATCH 144/146] qmetatype: add '-bigobj' flag to Windows ICC builds Fix 'Too many segments for object format' errors for (Debug) builds using Windows ICC. Change-Id: Ie48f43199948477c426d0a4e557f039eda129b22 Reviewed-by: Thiago Macieira --- tests/auto/corelib/kernel/qmetatype/qmetatype.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro index b5f1d0fe00e..ad148ccc7f2 100644 --- a/tests/auto/corelib/kernel/qmetatype/qmetatype.pro +++ b/tests/auto/corelib/kernel/qmetatype/qmetatype.pro @@ -6,7 +6,7 @@ SOURCES = tst_qmetatype.cpp TESTDATA=./typeFlags.bin DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 -win32-msvc*|winrt { +msvc|winrt { # Prevents "fatal error C1128: number of sections exceeded object file format limit". QMAKE_CXXFLAGS += /bigobj # Reduce compile time From 8db9e33997a8fbe3e13eab1ca62ae2d5ac39abef Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Tue, 6 Feb 2018 01:28:20 +0300 Subject: [PATCH 145/146] xcb: Enhance SHM management code - extract the creation of a shared memory segment into a separate function - do extra checks for errors - check that MIT-SHM extension is present once in QXcbConnection Change-Id: I956bdf76b879ec5c95a7ed219a59ae722dc5afba Reviewed-by: Gatis Paeglis --- .../platforms/xcb/qxcbbackingstore.cpp | 103 +++++++++++------- src/plugins/platforms/xcb/qxcbconnection.cpp | 28 ++++- src/plugins/platforms/xcb/qxcbconnection.h | 4 + 3 files changed, 91 insertions(+), 44 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 1cf45c96d13..e69bc5cba57 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -85,6 +85,9 @@ public: void preparePaint(const QRegion ®ion); private: + void createShmSegment(size_t segmentSize); + void destroyShmSegment(); + void destroy(); void ensureGC(xcb_drawable_t dst); @@ -173,39 +176,13 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI XCB_IMAGE_ORDER_MSB_FIRST, 0, ~0, 0); - const int segmentSize = m_xcb_image->stride * m_xcb_image->height; + const size_t segmentSize = static_cast(m_xcb_image->stride) * m_xcb_image->height; if (!segmentSize) return; - int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); - if (id == -1) { - qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %d (%dx%d)", - errno, strerror(errno), segmentSize, size.width(), size.height()); - } else { - m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat(id, 0, 0); - } - m_shm_info.shmid = id; - m_shm_info.shmseg = xcb_generate_id(xcb_connection()); + createShmSegment(segmentSize); - const xcb_query_extension_reply_t *shm_reply = xcb_get_extension_data(xcb_connection(), &xcb_shm_id); - bool shm_present = shm_reply != NULL && shm_reply->present; - xcb_generic_error_t *error = NULL; - if (shm_present) - error = xcb_request_check(xcb_connection(), xcb_shm_attach_checked(xcb_connection(), m_shm_info.shmseg, m_shm_info.shmid, false)); - if (!shm_present || error || id == -1) { - free(error); - - if (id != -1) { - shmdt(m_shm_info.shmaddr); - shmctl(m_shm_info.shmid, IPC_RMID, 0); - } - m_shm_info.shmaddr = 0; - - m_xcb_image->data = (uint8_t *)malloc(segmentSize); - } else { - if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1) - qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed"); - } + m_xcb_image->data = m_shm_info.shmaddr ? m_shm_info.shmaddr : (uint8_t *)malloc(segmentSize); m_hasAlpha = QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha; if (!m_hasAlpha) @@ -270,6 +247,60 @@ void QXcbShmImage::flushScrolledRegion(bool clientSideScroll) } } +void QXcbShmImage::createShmSegment(size_t segmentSize) +{ + m_shm_info.shmaddr = nullptr; + if (!connection()->hasShm()) + return; + + const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); + if (id == -1) { + qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %zu", + errno, strerror(errno), segmentSize); + return; + } + + void *addr = shmat(id, 0, 0); + if (addr == (void *)-1) { + qWarning("QXcbShmImage: shmat() failed (%d: %s) for id %d", + errno, strerror(errno), id); + return; + } + + if (shmctl(id, IPC_RMID, 0) == -1) + qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed"); + + const auto seg = xcb_generate_id(xcb_connection()); + auto cookie = xcb_shm_attach_checked(xcb_connection(), seg, id, false); + auto *error = xcb_request_check(xcb_connection(), cookie); + if (error) { + connection()->printXcbError("QXcbShmImage: xcb_shm_attach() failed with error", error); + free(error); + if (shmdt(addr) == -1) { + qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", + errno, strerror(errno), addr); + } + return; + } + + m_shm_info.shmseg = seg; + m_shm_info.shmid = id; // unused + m_shm_info.shmaddr = static_cast(addr); +} + +void QXcbShmImage::destroyShmSegment() +{ + auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg); + xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); + if (error) + connection()->printXcbError("QXcbShmImage: xcb_shm_detach() failed with error", error); + + if (shmdt(m_shm_info.shmaddr) == -1) { + qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", + errno, strerror(errno), m_shm_info.shmaddr); + } +} + extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy) @@ -318,17 +349,11 @@ bool QXcbShmImage::scroll(const QRegion &area, int dx, int dy) void QXcbShmImage::destroy() { - const int segmentSize = m_xcb_image ? (m_xcb_image->stride * m_xcb_image->height) : 0; - if (segmentSize && m_shm_info.shmaddr) - xcb_shm_detach(xcb_connection(), m_shm_info.shmseg); - - if (segmentSize) { - if (m_shm_info.shmaddr) { - shmdt(m_shm_info.shmaddr); - shmctl(m_shm_info.shmid, IPC_RMID, 0); - } else { + if (m_xcb_image->data) { + if (m_shm_info.shmaddr) + destroyShmSegment(); + else free(m_xcb_image->data); - } } xcb_image_destroy(m_xcb_image); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index c5eae20266b..e8bb97c6afb 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -582,6 +582,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeAllAtoms(); + initializeShm(); if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR")) initializeXRandr(); if (!has_randr_extension) @@ -961,14 +962,20 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result)) return; + printXcbError("QXcbConnection: XCB error", error); +} + +void QXcbConnection::printXcbError(const char *message, xcb_generic_error_t *error) +{ uint clamped_error_code = qMin(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); - qWarning("QXcbConnection: XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", - int(error->error_code), xcb_errors[clamped_error_code], - int(error->sequence), int(error->resource_id), - int(error->major_code), xcb_protocol_request_codes[clamped_major_code], - int(error->minor_code)); + qWarning("%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", + message, + int(error->error_code), xcb_errors[clamped_error_code], + int(error->sequence), int(error->resource_id), + int(error->major_code), xcb_protocol_request_codes[clamped_major_code], + int(error->minor_code)); } static Qt::MouseButtons translateMouseButtons(int s) @@ -2087,6 +2094,17 @@ void QXcbConnection::sync() free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0)); } +void QXcbConnection::initializeShm() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_shm_id); + if (!reply || !reply->present) { + qWarning("QXcbConnection: MIT-SHM extension is not present on the X server."); + return; + } + + has_shm = true; +} + void QXcbConnection::initializeXFixes() { const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 07df963ec57..b2713b8ac79 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -441,6 +441,7 @@ public: void sync(); void handleXcbError(xcb_generic_error_t *error); + void printXcbError(const char *message, xcb_generic_error_t *error); void handleXcbEvent(xcb_generic_event_t *event); void printXcbEvent(const QLoggingCategory &log, const char *message, xcb_generic_event_t *event) const; @@ -478,6 +479,7 @@ public: bool hasXKB() const { return has_xkb; } bool hasXRender() const { return has_render_extension; } bool hasXInput2() const { return m_xi2Enabled; } + bool hasShm() const { return has_shm; } bool threadedEventHandling() const { return m_reader->isRunning(); } @@ -545,6 +547,7 @@ private slots: private: void initializeAllAtoms(); void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); + void initializeShm(); void initializeXFixes(); void initializeXRender(); void initializeXRandr(); @@ -699,6 +702,7 @@ private: bool has_input_shape; bool has_xkb = false; bool has_render_extension = false; + bool has_shm = false; Qt::MouseButtons m_buttonState = 0; Qt::MouseButton m_button = Qt::NoButton; From 24adaa9a742e6f95ff897d0eb9a2bce0527dd042 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Tue, 6 Feb 2018 13:49:42 +0300 Subject: [PATCH 146/146] xcb: Fix access to shm for X server running from another user Use ShmCreateSegment call, that was added in MIT-SHM 1.2, to create shared memory segments on the server side. It returns a POSIX shared memory object that is used to mmap memory. It's in effect a file descriptor that is passed through the X server socket and thus avoids permission checks. On the other hand this scheme is more secure, because the file descriptor, and thus the shared memory, are accessible only by the X server and the application. Task-number: QTBUG-46017 Change-Id: I202eead9d01aee2ab5b65f4f74f4c13da7cb2239 Reviewed-by: Gatis Paeglis --- .../platforms/xcb/qxcbbackingstore.cpp | 139 +++++++++++++----- src/plugins/platforms/xcb/qxcbconnection.cpp | 9 ++ src/plugins/platforms/xcb/qxcbconnection.h | 2 + 3 files changed, 112 insertions(+), 38 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index e69bc5cba57..eae0ee76131 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -48,9 +48,11 @@ #include #include +#include #include #include +#include #include #include @@ -61,6 +63,11 @@ #include #include + +#if (XCB_SHM_MAJOR_VERSION == 1 && XCB_SHM_MINOR_VERSION >= 2) || XCB_SHM_MAJOR_VERSION > 1 +#define XCB_USE_SHM_FD +#endif + QT_BEGIN_NAMESPACE class QXcbShmImage : public QXcbObject @@ -86,7 +93,7 @@ public: private: void createShmSegment(size_t segmentSize); - void destroyShmSegment(); + void destroyShmSegment(size_t segmentSize); void destroy(); @@ -157,6 +164,11 @@ private: QImage *m_image; }; +static inline size_t imageDataSize(const xcb_image_t *image) +{ + return static_cast(image->stride) * image->height; +} + QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format) : QXcbObject(screen->connection()) , m_graphics_buffer(nullptr) @@ -176,7 +188,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI XCB_IMAGE_ORDER_MSB_FIRST, 0, ~0, 0); - const size_t segmentSize = static_cast(m_xcb_image->stride) * m_xcb_image->height; + const size_t segmentSize = imageDataSize(m_xcb_image); if (!segmentSize) return; @@ -250,54 +262,105 @@ void QXcbShmImage::flushScrolledRegion(bool clientSideScroll) void QXcbShmImage::createShmSegment(size_t segmentSize) { m_shm_info.shmaddr = nullptr; + if (!connection()->hasShm()) return; - const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); - if (id == -1) { - qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %zu", - errno, strerror(errno), segmentSize); - return; - } - - void *addr = shmat(id, 0, 0); - if (addr == (void *)-1) { - qWarning("QXcbShmImage: shmat() failed (%d: %s) for id %d", - errno, strerror(errno), id); - return; - } - - if (shmctl(id, IPC_RMID, 0) == -1) - qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed"); - - const auto seg = xcb_generate_id(xcb_connection()); - auto cookie = xcb_shm_attach_checked(xcb_connection(), seg, id, false); - auto *error = xcb_request_check(xcb_connection(), cookie); - if (error) { - connection()->printXcbError("QXcbShmImage: xcb_shm_attach() failed with error", error); - free(error); - if (shmdt(addr) == -1) { - qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", - errno, strerror(errno), addr); +#ifdef XCB_USE_SHM_FD + if (connection()->hasShmFd()) { + if (Q_UNLIKELY(segmentSize > std::numeric_limits::max())) { + qWarning("QXcbShmImage: xcb_shm_create_segment() can't be called for size %zu, maximum allowed size is %u", + segmentSize, std::numeric_limits::max()); + return; + } + const auto seg = xcb_generate_id(xcb_connection()); + auto reply = Q_XCB_REPLY(xcb_shm_create_segment, + xcb_connection(), seg, segmentSize, false); + if (!reply) { + qWarning("QXcbShmImage: xcb_shm_create_segment() failed for size %zu", segmentSize); + return; } - return; - } - m_shm_info.shmseg = seg; - m_shm_info.shmid = id; // unused - m_shm_info.shmaddr = static_cast(addr); + int *fds = xcb_shm_create_segment_reply_fds(xcb_connection(), reply.get()); + if (reply->nfd != 1) { + for (int i = 0; i < reply->nfd; i++) + close(fds[i]); + + qWarning("QXcbShmImage: failed to get file descriptor for shm segment of size %zu", segmentSize); + return; + } + + void *addr = mmap(nullptr, segmentSize, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0); + if (addr == MAP_FAILED) { + qWarning("QXcbShmImage: failed to mmap segment from X server (%d: %s) for size %zu", + errno, strerror(errno), segmentSize); + close(fds[0]); + xcb_shm_detach(xcb_connection(), seg); + return; + } + + close(fds[0]); + m_shm_info.shmseg = seg; + m_shm_info.shmaddr = static_cast(addr); + } else +#endif + { + const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); + if (id == -1) { + qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %zu", + errno, strerror(errno), segmentSize); + return; + } + + void *addr = shmat(id, 0, 0); + if (addr == (void *)-1) { + qWarning("QXcbShmImage: shmat() failed (%d: %s) for id %d", + errno, strerror(errno), id); + return; + } + + if (shmctl(id, IPC_RMID, 0) == -1) + qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed"); + + const auto seg = xcb_generate_id(xcb_connection()); + auto cookie = xcb_shm_attach_checked(xcb_connection(), seg, id, false); + auto *error = xcb_request_check(xcb_connection(), cookie); + if (error) { + connection()->printXcbError("QXcbShmImage: xcb_shm_attach() failed with error", error); + free(error); + if (shmdt(addr) == -1) { + qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", + errno, strerror(errno), addr); + } + return; + } + + m_shm_info.shmseg = seg; + m_shm_info.shmid = id; // unused + m_shm_info.shmaddr = static_cast(addr); + } } -void QXcbShmImage::destroyShmSegment() +void QXcbShmImage::destroyShmSegment(size_t segmentSize) { auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) connection()->printXcbError("QXcbShmImage: xcb_shm_detach() failed with error", error); - if (shmdt(m_shm_info.shmaddr) == -1) { - qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", - errno, strerror(errno), m_shm_info.shmaddr); +#ifdef XCB_USE_SHM_FD + if (connection()->hasShmFd()) { + if (munmap(m_shm_info.shmaddr, segmentSize) == -1) { + qWarning("QXcbShmImage: munmap() failed (%d: %s) for %p with size %zu", + errno, strerror(errno), m_shm_info.shmaddr, segmentSize); + } + } else +#endif + { + if (shmdt(m_shm_info.shmaddr) == -1) { + qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", + errno, strerror(errno), m_shm_info.shmaddr); + } } } @@ -351,7 +414,7 @@ void QXcbShmImage::destroy() { if (m_xcb_image->data) { if (m_shm_info.shmaddr) - destroyShmSegment(); + destroyShmSegment(imageDataSize(m_xcb_image)); else free(m_xcb_image->data); } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index e8bb97c6afb..d0868f44c0e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -2103,6 +2103,15 @@ void QXcbConnection::initializeShm() } has_shm = true; + + auto shm_query = Q_XCB_REPLY(xcb_shm_query_version, m_connection); + if (!shm_query) { + qWarning("QXcbConnection: Failed to request MIT-SHM version"); + return; + } + + has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) || + shm_query->major_version > 1; } void QXcbConnection::initializeXFixes() diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index b2713b8ac79..dbc1c4561de 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -480,6 +480,7 @@ public: bool hasXRender() const { return has_render_extension; } bool hasXInput2() const { return m_xi2Enabled; } bool hasShm() const { return has_shm; } + bool hasShmFd() const { return has_shm_fd; } bool threadedEventHandling() const { return m_reader->isRunning(); } @@ -703,6 +704,7 @@ private: bool has_xkb = false; bool has_render_extension = false; bool has_shm = false; + bool has_shm_fd = false; Qt::MouseButtons m_buttonState = 0; Qt::MouseButton m_button = Qt::NoButton;