summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.cpp47
-rw-r--r--config.tests/win/angle_d3d11_qdtd/angle_d3d11_qdtd.pro3
-rw-r--r--config_help.txt3
-rw-r--r--dist/changes-5.9.46
-rw-r--r--doc/global/macros.qdocconf1
-rw-r--r--examples/corelib/ipc/ipc.pro6
-rw-r--r--examples/opengl/hellogles3/main.cpp4
-rw-r--r--mkspecs/common/msvc-desktop.conf6
-rw-r--r--mkspecs/common/msvc-version.conf5
-rw-r--r--mkspecs/features/android/android_deployment_settings.prf2
-rw-r--r--mkspecs/features/qt_example_installs.prf18
-rw-r--r--mkspecs/features/testcase.prf2
-rw-r--r--mkspecs/win32-g++/qmake.conf9
-rw-r--r--mkspecs/win32-icc/qmake.conf15
-rw-r--r--qmake/doc/src/qmake-manual.qdoc3
-rw-r--r--qmake/library/ioutils.cpp23
-rw-r--r--qmake/library/qmakebuiltins.cpp13
-rw-r--r--qmake/library/qmakeglobals.cpp15
-rw-r--r--qmake/option.cpp5
-rw-r--r--src/3rdparty/angle/src/libANGLE/Debug2.cpp303
-rw-r--r--src/3rdparty/angle/src/libANGLE/Debug2.h120
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/CursorHandle.java27
-rw-r--r--src/angle/src/common/gles_common.pri12
-rw-r--r--src/concurrent/doc/src/qtconcurrent-index.qdoc11
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp2
-rw-r--r--src/corelib/doc/src/qtcore-index.qdoc7
-rw-r--r--src/corelib/global/qglobal.cpp6
-rw-r--r--src/corelib/global/qlogging.cpp4
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp4
-rw-r--r--src/corelib/io/io.pri2
-rw-r--r--src/corelib/io/qloggingregistry.cpp10
-rw-r--r--src/corelib/io/qprocess_win.cpp3
-rw-r--r--src/corelib/io/qsettings.cpp5
-rw-r--r--src/corelib/io/qstandardpaths_android.cpp15
-rw-r--r--src/corelib/io/qurlrecode.cpp4
-rw-r--r--src/corelib/json/qjsonarray.cpp1238
-rw-r--r--src/corelib/kernel/kernel.pri2
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp14
-rw-r--r--src/corelib/plugin/qlibrary.cpp29
-rw-r--r--src/corelib/plugin/qlibrary_unix.cpp35
-rw-r--r--src/corelib/tools/qarraydataops.h3
-rw-r--r--src/corelib/tools/qstring.cpp14
-rw-r--r--src/corelib/tools/qtimezone.cpp8
-rw-r--r--src/corelib/tools/qtimezoneprivate_p.h6
-rw-r--r--src/corelib/tools/qvarlengtharray.h4
-rw-r--r--src/corelib/tools/qvector.h2
-rw-r--r--src/corelib/tools/tools.pri2
-rw-r--r--src/corelib/xml/qxmlstream_p.h1966
-rw-r--r--src/dbus/doc/src/qtdbus-index.qdoc11
-rw-r--r--src/gui/configure.json21
-rw-r--r--src/gui/doc/src/qtgui.qdoc5
-rw-r--r--src/gui/kernel/qguiapplication.cpp4
-rw-r--r--src/gui/kernel/qopenglcontext.cpp1
-rw-r--r--src/gui/kernel/qplatforminputcontext.cpp2
-rw-r--r--src/gui/kernel/qsimpledrag.cpp30
-rw-r--r--src/gui/kernel/qsimpledrag_p.h6
-rw-r--r--src/gui/painting/qmatrix.h4
-rw-r--r--src/gui/painting/qtransform.h6
-rw-r--r--src/gui/text/qtextengine_p.h8
-rw-r--r--src/gui/text/qtextobject.h4
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp2
-rw-r--r--src/network/ssl/qsslsocket_p.h2
-rw-r--r--src/network/ssl/ssl.pri2
-rw-r--r--src/opengl/doc/src/qtopengl-index.qdoc17
-rw-r--r--src/platformsupport/eglconvenience/qeglplatformcontext.cpp4
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp4
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h2
-rw-r--r--src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm37
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm8
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h2
-rw-r--r--src/plugins/bearer/bearer.pro2
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp58
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm18
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm12
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp2
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp6
-rw-r--r--src/plugins/platforms/platforms.pro4
-rw-r--r--src/plugins/platforms/qnx/qnx.pro4
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.cpp130
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.h16
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.cpp206
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.h30
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp53
-rw-r--r--src/plugins/platforms/qnx/qqnxnativeinterface.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.h10
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp27
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp4
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3menu.cpp9
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.cpp17
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.h2
-rw-r--r--src/printsupport/doc/src/qtprintsupport-index.qdoc15
-rw-r--r--src/sql/doc/src/qtsql.qdoc5
-rw-r--r--src/src.pro8
-rw-r--r--src/testlib/doc/src/qttest-index.qdoc5
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp5
-rw-r--r--src/widgets/doc/src/qtwidgets-index.qdoc11
-rw-r--r--src/widgets/itemviews/qheaderview.cpp88
-rw-r--r--src/widgets/itemviews/qheaderview_p.h11
-rw-r--r--src/widgets/itemviews/qtreeview.cpp2
-rw-r--r--src/widgets/kernel/qwidget.cpp3
-rw-r--r--src/widgets/styles/qfusionstyle.cpp8
-rw-r--r--src/widgets/styles/qmacstyle_mac.mm7160
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp5
-rw-r--r--src/widgets/util/qsystemtrayicon.cpp7
-rw-r--r--src/widgets/widgets/qcombobox.cpp4
-rw-r--r--src/xml/doc/src/qtxml-index.qdoc11
-rw-r--r--src/xml/sax/qxml.cpp14
-rw-r--r--tests/auto/concurrent/qtconcurrentmap/BLACKLIST1
-rw-r--r--tests/auto/corelib/io/qdir/qdir.pro2
-rw-r--r--tests/auto/corelib/io/qdir/tst_qdir.cpp6
-rw-r--r--tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp2
-rw-r--r--tests/auto/corelib/io/qfile/tst_qfile.cpp9
-rw-r--r--tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp4
-rw-r--r--tests/auto/corelib/io/qfilesystemwatcher/tst_qfilesystemwatcher.cpp2
-rw-r--r--tests/auto/corelib/io/qiodevice/qiodevice.pro2
-rw-r--r--tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp2
-rw-r--r--tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp2
-rw-r--r--tests/auto/corelib/io/qloggingregistry/qloggingregistry.pro2
-rw-r--r--tests/auto/corelib/io/qresourceengine/qresourceengine.pro2
-rw-r--r--tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp6
-rw-r--r--tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp2
-rw-r--r--tests/auto/corelib/io/qtemporaryfile/qtemporaryfile.pro2
-rw-r--r--tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp8
-rw-r--r--tests/auto/corelib/kernel/qtranslator/qtranslator.pro2
-rw-r--r--tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp2
-rw-r--r--tests/auto/corelib/serialization/qdatastream/qdatastream.pro2
-rw-r--r--tests/auto/corelib/tools/qbytearray/qbytearray.pro2
-rw-r--r--tests/auto/corelib/tools/qchar/qchar.pro2
-rw-r--r--tests/auto/corelib/tools/qcollator/tst_qcollator.cpp2
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp6
-rw-r--r--tests/auto/corelib/tools/qcryptographichash/qcryptographichash.pro2
-rw-r--r--tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp1
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/externaltests.cpp15
-rw-r--r--tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro2
-rw-r--r--tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp14
-rw-r--r--tests/auto/gui/image/qimage/qimage.pro2
-rw-r--r--tests/auto/gui/image/qimagereader/qimagereader.pro2
-rw-r--r--tests/auto/gui/image/qimagewriter/qimagewriter.pro2
-rw-r--r--tests/auto/gui/kernel/qwindow/BLACKLIST2
-rw-r--r--tests/auto/gui/painting/qpainter/qpainter.pro2
-rw-r--r--tests/auto/gui/text/qrawfont/tst_qrawfont.cpp39
-rw-r--r--tests/auto/network/access/qftp/tst_qftp.cpp1
-rw-r--r--tests/auto/network/access/qnetworkreply/BLACKLIST3
-rw-r--r--tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp9
-rw-r--r--tests/auto/network/socket/qtcpsocket/BLACKLIST4
-rw-r--r--tests/auto/other/qprocess_and_guieventloop/tst_qprocess_and_guieventloop.cpp2
-rw-r--r--tests/auto/tools/qmakelib/evaltest.cpp46
-rw-r--r--tests/auto/tools/qmakelib/tst_qmakelib.cpp97
-rw-r--r--tests/auto/tools/qmakelib/tst_qmakelib.h5
-rw-r--r--tests/auto/widgets/dialogs/qmessagebox/BLACKLIST2
-rw-r--r--tests/auto/widgets/dialogs/qsidebar/tst_qsidebar.cpp2
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp6
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/qdirmodel.pro2
-rw-r--r--tests/auto/widgets/itemviews/qdirmodel/tst_qdirmodel.cpp4
-rw-r--r--tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp13
-rw-r--r--tests/auto/widgets/kernel/qlayout/qlayout.pro2
-rw-r--r--tests/auto/widgets/kernel/qlayout/tst_qlayout.cpp2
-rw-r--r--tests/auto/widgets/styles/qstyle/qstyle.pro2
-rw-r--r--tests/auto/widgets/widgets/qmenubar/BLACKLIST3
-rw-r--r--tests/auto/widgets/widgets/qscrollbar/BLACKLIST3
-rw-r--r--tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp84
166 files changed, 11515 insertions, 1150 deletions
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 2dde2914a2..0000000000
--- 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 <D3D11.h>
-
-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 f1e530ab6e..0000000000
--- 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/config_help.txt b/config_help.txt
index 5c57e30d63..4be797cc6b 100644
--- a/config_help.txt
+++ b/config_help.txt
@@ -126,6 +126,9 @@ Build options:
-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 <edition> .... Select C++ standard <edition> [c++1z/c++14/c++11]
(Not supported with MSVC)
diff --git a/dist/changes-5.9.4 b/dist/changes-5.9.4
index 0bb768424f..f0cc6007c2 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
diff --git a/doc/global/macros.qdocconf b/doc/global/macros.qdocconf
index 5544da425a..dbf8c5cc6a 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 = "<sup>*</sup>"
macro.rarrow.HTML = "&rarr;"
diff --git a/examples/corelib/ipc/ipc.pro b/examples/corelib/ipc/ipc.pro
index 101552cea9..68c88d75aa 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
+}
diff --git a/examples/opengl/hellogles3/main.cpp b/examples/opengl/hellogles3/main.cpp
index a6c6398628..29b3b9617a 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();
diff --git a/mkspecs/common/msvc-desktop.conf b/mkspecs/common/msvc-desktop.conf
index 1a38f70205..b7d2eecc82 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
@@ -94,7 +95,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 9f5da91806..ccd809abf3 100644
--- a/mkspecs/common/msvc-version.conf
+++ b/mkspecs/common/msvc-version.conf
@@ -100,6 +100,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/features/android/android_deployment_settings.prf b/mkspecs/features/android/android_deployment_settings.prf
index 913ab71412..e6b2431f9a 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/mkspecs/features/qt_example_installs.prf b/mkspecs/features/qt_example_installs.prf
index 668669e4cd..c9ce926b1a 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]*<file[^>]*>([^<]+)</file>[ \\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 += \
diff --git a/mkspecs/features/testcase.prf b/mkspecs/features/testcase.prf
index 3e1537dde0..8d51c9d028 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)
}
diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf
index d728047765..12f3567754 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
@@ -32,6 +35,8 @@ QMAKE_CFLAGS_AESNI = -maes
QMAKE_CFLAGS_SHANI = -msha
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 a539bfba72..cc9c6e7363 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
@@ -46,7 +49,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
diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc
index 8b7d1b0853..cc3b73418b 100644
--- a/qmake/doc/src/qmake-manual.qdoc
+++ b/qmake/doc/src/qmake-manual.qdoc
@@ -2359,6 +2359,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.
diff --git a/qmake/library/ioutils.cpp b/qmake/library/ioutils.cpp
index 684bcb9a37..afd41912fe 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 759bff314e..83c3d1d643 100644
--- a/qmake/library/qmakebuiltins.cpp
+++ b/qmake/library/qmakebuiltins.cpp
@@ -1177,9 +1177,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)
@@ -1191,9 +1191,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 b6dc8b20b6..d733d479cf 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/qmake/option.cpp b/qmake/option.cpp
index 9737f1f680..baad644280 100644
--- a/qmake/option.cpp
+++ b/qmake/option.cpp
@@ -28,6 +28,7 @@
#include "option.h"
#include "cachekeys.h"
+#include <ioutils.h>
#include <qdir.h>
#include <qregexp.h>
#include <qhash.h>
@@ -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
diff --git a/src/3rdparty/angle/src/libANGLE/Debug2.cpp b/src/3rdparty/angle/src/libANGLE/Debug2.cpp
deleted file mode 100644
index 30321f4160..0000000000
--- 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 <algorithm>
-#include <tuple>
-
-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<GLsizei>(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<size_t>(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<GLsizei>(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<GLuint> &&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 f545b815e4..0000000000
--- 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 <deque>
-#include <string>
-#include <vector>
-
-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<GLuint> &&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<GLuint> ids;
- bool enabled;
- };
-
- struct Group
- {
- GLenum source;
- GLuint id;
- std::string message;
-
- std::vector<Control> controls;
- };
-
- bool mOutputEnabled;
- GLDEBUGPROCKHR mCallbackFunction;
- const void *mCallbackUserParam;
- std::deque<Message> mMessages;
- GLuint mMaxLoggedMessages;
- bool mOutputSynchronous;
- std::vector<Group> mGroups;
-};
-} // namespace gl
-
-#endif // LIBANGLE_DEBUG_H_
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 e6814c202d..4f2c06644d 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,9 @@ 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;
+ private boolean m_pressed = false;
CursorView (Context context, CursorHandle handle) {
super(context);
@@ -76,21 +78,23 @@ 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;
+ m_pressed = true;
break;
}
case MotionEvent.ACTION_MOVE: {
- mHandle.updatePosition(Math.round(ev.getRawX()) - m_offsetX,
- Math.round(ev.getRawY()) - m_offsetY);
+ if (!m_pressed)
+ return false;
+ mHandle.updatePosition(Math.round(ev.getRawX() - m_offsetX),
+ Math.round(ev.getRawY() - m_offsetY));
break;
}
case MotionEvent.ACTION_UP:
- break;
-
case MotionEvent.ACTION_CANCEL:
+ m_pressed = false;
break;
}
return true;
@@ -113,6 +117,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 +126,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 +164,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 +193,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;
diff --git a/src/angle/src/common/gles_common.pri b/src/angle/src/common/gles_common.pri
index 5d5682a1df..82d38a62e6 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 \
diff --git a/src/concurrent/doc/src/qtconcurrent-index.qdoc b/src/concurrent/doc/src/qtconcurrent-index.qdoc
index 836cde131c..3e4aa791f1 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/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp b/src/corelib/doc/snippets/code/src_corelib_concurrent_qthreadpool.cpp
index a1372976ae..ba31972aa1 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
diff --git a/src/corelib/doc/src/qtcore-index.qdoc b/src/corelib/doc/src/qtcore-index.qdoc
index 9004c018ed..04af0e9416 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/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 1fe1c8c0d1..2d8b860c5b 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -84,7 +84,7 @@
# include <envLib.h>
#endif
-#if defined(Q_OS_ANDROID)
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
#include <private/qjni_p.h>
#endif
@@ -2298,7 +2298,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:
@@ -2779,7 +2779,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)
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 39a5bbf645..9f1fe7cabb 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -1597,7 +1597,7 @@ static bool syslog_default_message_handler(QtMsgType type, const QMessageLogCont
}
#endif
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
static bool android_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
const QString &message)
@@ -1678,7 +1678,7 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con
handledStderr |= systemd_default_message_handler(type, context, message);
# elif QT_CONFIG(syslog)
handledStderr |= syslog_default_message_handler(type, context, message);
-# elif defined(Q_OS_ANDROID)
+# elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
handledStderr |= android_default_message_handler(type, context, message);
# elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index 682c9bab61..4d267e328d 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -45,7 +45,7 @@
#include <qversionnumber.h>
#include <qdebug.h>
-#if defined(Q_OS_ANDROID)
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
#include <private/qjni_p.h>
#endif
@@ -163,7 +163,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 c6a5973306..d138ab2f00 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -159,7 +159,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/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index b5f8e30b80..cd97268d71 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -44,6 +44,7 @@
#include <QtCore/qstandardpaths.h>
#include <QtCore/qtextstream.h>
#include <QtCore/qdir.h>
+#include <QtCore/qcoreapplication.h>
// 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/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 6ab806d9fe..3a62a67e3b 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -101,7 +101,8 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
unsigned int attempts = 1000;
forever {
_snwprintf(pipeName, sizeof(pipeName) / sizeof(pipeName[0]),
- L"\\\\.\\pipe\\qt-%X", QRandomGenerator::global()->generate());
+ L"\\\\.\\pipe\\qt-%lX-%X", long(QCoreApplication::applicationPid()),
+ QRandomGenerator::global()->generate());
DWORD dwOpenMode = FILE_FLAG_OVERLAPPED;
DWORD dwOutputBufferSize = 0;
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index bbc66120b5..4b1b9888d8 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -2366,6 +2366,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.
diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp
index 2a44daf8b5..0667d170c7 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));
diff --git a/src/corelib/io/qurlrecode.cpp b/src/corelib/io/qurlrecode.cpp
index ce90ab49d3..a9b23babc0 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<void *>(appendTo.begin() + origSize), static_cast<const void *>(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<ushort *>(appendTo.begin()) + origSize;
- memcpy(output, begin, (input - begin) * sizeof(ushort));
+ memcpy(static_cast<void *>(output), static_cast<const void *>(begin), (input - begin) * sizeof(ushort));
output += input - begin;
}
diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp
new file mode 100644
index 0000000000..255dc2ee4e
--- /dev/null
+++ b/src/corelib/json/qjsonarray.cpp
@@ -0,0 +1,1238 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore 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$
+**
+****************************************************************************/
+
+#include <qjsonobject.h>
+#include <qjsonvalue.h>
+#include <qjsonarray.h>
+#include <qstringlist.h>
+#include <qvariant.h>
+#include <qdebug.h>
+
+#include "qjsonwriter_p.h"
+#include "qjson_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QJsonArray
+ \inmodule QtCore
+ \ingroup json
+ \ingroup shared
+ \reentrant
+ \since 5.0
+
+ \brief The QJsonArray class encapsulates a JSON array.
+
+ A JSON array is a list of values. The list can be manipulated by inserting and
+ removing QJsonValue's from the array.
+
+ A QJsonArray can be converted to and from a QVariantList. You can query the
+ number of entries with size(), insert(), and removeAt() entries from it
+ and iterate over its content using the standard C++ iterator pattern.
+
+ QJsonArray is an implicitly shared class and shares the data with the document
+ it has been created from as long as it is not being modified.
+
+ You can convert the array to and from text based JSON through QJsonDocument.
+
+ \sa {JSON Support in Qt}, {JSON Save Game Example}
+*/
+
+/*!
+ \typedef QJsonArray::Iterator
+
+ Qt-style synonym for QJsonArray::iterator.
+*/
+
+/*!
+ \typedef QJsonArray::ConstIterator
+
+ Qt-style synonym for QJsonArray::const_iterator.
+*/
+
+/*!
+ \typedef QJsonArray::size_type
+
+ Typedef for int. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QJsonArray::value_type
+
+ Typedef for QJsonValue. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QJsonArray::difference_type
+
+ Typedef for int. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QJsonArray::pointer
+
+ Typedef for QJsonValue *. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QJsonArray::const_pointer
+
+ Typedef for const QJsonValue *. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QJsonArray::reference
+
+ Typedef for QJsonValue &. Provided for STL compatibility.
+*/
+
+/*!
+ \typedef QJsonArray::const_reference
+
+ Typedef for const QJsonValue &. Provided for STL compatibility.
+*/
+
+/*!
+ Creates an empty array.
+ */
+QJsonArray::QJsonArray()
+ : d(0), a(0)
+{
+}
+
+/*!
+ \fn QJsonArray::QJsonArray(std::initializer_list<QJsonValue> args)
+ \since 5.4
+ Creates an array initialized from \a args initialization list.
+
+ QJsonArray can be constructed in a way similar to JSON notation,
+ for example:
+ \code
+ QJsonArray array = { 1, 2.2, QString() };
+ \endcode
+ */
+
+/*!
+ \internal
+ */
+QJsonArray::QJsonArray(QJsonPrivate::Data *data, QJsonPrivate::Array *array)
+ : d(data), a(array)
+{
+ Q_ASSERT(data);
+ Q_ASSERT(array);
+ d->ref.ref();
+}
+
+/*!
+ This method replaces part of QJsonArray(std::initializer_list<QJsonValue> args) .
+ The constructor needs to be inline, but we do not want to leak implementation details
+ of this class.
+ \note this method is called for an uninitialized object
+ \internal
+ */
+void QJsonArray::initialize()
+{
+ d = 0;
+ a = 0;
+}
+
+/*!
+ Deletes the array.
+ */
+QJsonArray::~QJsonArray()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Creates a copy of \a other.
+
+ Since QJsonArray is implicitly shared, the copy is shallow
+ as long as the object doesn't get modified.
+ */
+QJsonArray::QJsonArray(const QJsonArray &other)
+{
+ d = other.d;
+ a = other.a;
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Assigns \a other to this array.
+ */
+QJsonArray &QJsonArray::operator =(const QJsonArray &other)
+{
+ if (d != other.d) {
+ if (d && !d->ref.deref())
+ delete d;
+ d = other.d;
+ if (d)
+ d->ref.ref();
+ }
+ a = other.a;
+
+ return *this;
+}
+
+/*! \fn QJsonArray &QJsonArray::operator+=(const QJsonValue &value)
+
+ Appends \a value to the array, and returns a reference to the array itself.
+
+ \since 5.3
+ \sa append(), operator<<()
+*/
+
+/*! \fn QJsonArray QJsonArray::operator+(const QJsonValue &value) const
+
+ Returns an array that contains all the items in this array followed
+ by the provided \a value.
+
+ \since 5.3
+ \sa operator+=()
+*/
+
+/*! \fn QJsonArray &QJsonArray::operator<<(const QJsonValue &value)
+
+ Appends \a value to the array, and returns a reference to the array itself.
+
+ \since 5.3
+ \sa operator+=(), append()
+*/
+
+/*!
+ Converts the string list \a list to a QJsonArray.
+
+ The values in \a list will be converted to JSON values.
+
+ \sa toVariantList(), QJsonValue::fromVariant()
+ */
+QJsonArray QJsonArray::fromStringList(const QStringList &list)
+{
+ QJsonArray array;
+ for (QStringList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it)
+ array.append(QJsonValue(*it));
+ return array;
+}
+
+/*!
+ Converts the variant list \a list to a QJsonArray.
+
+ The QVariant values in \a list will be converted to JSON values.
+
+ \sa toVariantList(), QJsonValue::fromVariant()
+ */
+QJsonArray QJsonArray::fromVariantList(const QVariantList &list)
+{
+ QJsonArray array;
+ if (list.isEmpty())
+ return array;
+
+ array.detach2(1024);
+
+ QVector<QJsonPrivate::Value> values;
+ values.resize(list.size());
+ QJsonPrivate::Value *valueData = values.data();
+ uint currentOffset = sizeof(QJsonPrivate::Base);
+
+ for (int i = 0; i < list.size(); ++i) {
+ QJsonValue val = QJsonValue::fromVariant(list.at(i));
+
+ bool latinOrIntValue;
+ int valueSize = QJsonPrivate::Value::requiredStorage(val, &latinOrIntValue);
+
+ if (!array.detach2(valueSize))
+ return QJsonArray();
+
+ QJsonPrivate::Value *v = valueData + i;
+ v->type = (val.t == QJsonValue::Undefined ? QJsonValue::Null : val.t);
+ v->latinOrIntValue = latinOrIntValue;
+ v->latinKey = false;
+ v->value = QJsonPrivate::Value::valueToStore(val, currentOffset);
+ if (valueSize)
+ QJsonPrivate::Value::copyData(val, (char *)array.a + currentOffset, latinOrIntValue);
+
+ currentOffset += valueSize;
+ array.a->size = currentOffset;
+ }
+
+ // write table
+ array.a->tableOffset = currentOffset;
+ if (!array.detach2(sizeof(QJsonPrivate::offset)*values.size()))
+ return QJsonArray();
+ memcpy(static_cast<void *>(array.a->table()),
+ static_cast<const void *>(values.constData()), values.size()*sizeof(uint));
+ array.a->length = values.size();
+ array.a->size = currentOffset + sizeof(QJsonPrivate::offset)*values.size();
+
+ return array;
+}
+
+/*!
+ Converts this object to a QVariantList.
+
+ Returns the created map.
+ */
+QVariantList QJsonArray::toVariantList() const
+{
+ QVariantList list;
+
+ if (a) {
+ list.reserve(a->length);
+ for (int i = 0; i < (int)a->length; ++i)
+ list.append(QJsonValue(d, a, a->at(i)).toVariant());
+ }
+ return list;
+}
+
+
+/*!
+ Returns the number of values stored in the array.
+ */
+int QJsonArray::size() const
+{
+ if (!d)
+ return 0;
+
+ return (int)a->length;
+}
+
+/*!
+ \fn QJsonArray::count() const
+
+ Same as size().
+
+ \sa size()
+*/
+
+/*!
+ Returns \c true if the object is empty. This is the same as size() == 0.
+
+ \sa size()
+ */
+bool QJsonArray::isEmpty() const
+{
+ if (!d)
+ return true;
+
+ return !a->length;
+}
+
+/*!
+ Returns a QJsonValue representing the value for index \a i.
+
+ The returned QJsonValue is \c Undefined, if \a i is out of bounds.
+
+ */
+QJsonValue QJsonArray::at(int i) const
+{
+ if (!a || i < 0 || i >= (int)a->length)
+ return QJsonValue(QJsonValue::Undefined);
+
+ return QJsonValue(d, a, a->at(i));
+}
+
+/*!
+ Returns the first value stored in the array.
+
+ Same as \c at(0).
+
+ \sa at()
+ */
+QJsonValue QJsonArray::first() const
+{
+ return at(0);
+}
+
+/*!
+ Returns the last value stored in the array.
+
+ Same as \c{at(size() - 1)}.
+
+ \sa at()
+ */
+QJsonValue QJsonArray::last() const
+{
+ return at(a ? (a->length - 1) : 0);
+}
+
+/*!
+ Inserts \a value at the beginning of the array.
+
+ This is the same as \c{insert(0, value)} and will prepend \a value to the array.
+
+ \sa append(), insert()
+ */
+void QJsonArray::prepend(const QJsonValue &value)
+{
+ insert(0, value);
+}
+
+/*!
+ Inserts \a value at the end of the array.
+
+ \sa prepend(), insert()
+ */
+void QJsonArray::append(const QJsonValue &value)
+{
+ insert(a ? (int)a->length : 0, value);
+}
+
+/*!
+ Removes the value at index position \a i. \a i must be a valid
+ index position in the array (i.e., \c{0 <= i < size()}).
+
+ \sa insert(), replace()
+ */
+void QJsonArray::removeAt(int i)
+{
+ if (!a || i < 0 || i >= (int)a->length)
+ return;
+
+ detach2();
+ a->removeItems(i, 1);
+ ++d->compactionCounter;
+ if (d->compactionCounter > 32u && d->compactionCounter >= unsigned(a->length) / 2u)
+ compact();
+}
+
+/*! \fn void QJsonArray::removeFirst()
+
+ Removes the first item in the array. Calling this function is
+ equivalent to calling \c{removeAt(0)}. The array must not be empty. If
+ the array can be empty, call isEmpty() before calling this
+ function.
+
+ \sa removeAt(), removeLast()
+*/
+
+/*! \fn void QJsonArray::removeLast()
+
+ Removes the last item in the array. Calling this function is
+ equivalent to calling \c{removeAt(size() - 1)}. The array must not be
+ empty. If the array can be empty, call isEmpty() before calling
+ this function.
+
+ \sa removeAt(), removeFirst()
+*/
+
+/*!
+ Removes the item at index position \a i and returns it. \a i must
+ be a valid index position in the array (i.e., \c{0 <= i < size()}).
+
+ If you don't use the return value, removeAt() is more efficient.
+
+ \sa removeAt()
+ */
+QJsonValue QJsonArray::takeAt(int i)
+{
+ if (!a || i < 0 || i >= (int)a->length)
+ return QJsonValue(QJsonValue::Undefined);
+
+ QJsonValue v(d, a, a->at(i));
+ removeAt(i); // detaches
+ return v;
+}
+
+/*!
+ Inserts \a value at index position \a i in the array. If \a i
+ is \c 0, the value is prepended to the array. If \a i is size(), the
+ value is appended to the array.
+
+ \sa append(), prepend(), replace(), removeAt()
+ */
+void QJsonArray::insert(int i, const QJsonValue &value)
+{
+ Q_ASSERT (i >= 0 && i <= (a ? (int)a->length : 0));
+ QJsonValue val = value;
+
+ bool compressed;
+ int valueSize = QJsonPrivate::Value::requiredStorage(val, &compressed);
+
+ if (!detach2(valueSize + sizeof(QJsonPrivate::Value)))
+ return;
+
+ if (!a->length)
+ a->tableOffset = sizeof(QJsonPrivate::Array);
+
+ int valueOffset = a->reserveSpace(valueSize, i, 1, false);
+ if (!valueOffset)
+ return;
+
+ QJsonPrivate::Value &v = (*a)[i];
+ v.type = (val.t == QJsonValue::Undefined ? QJsonValue::Null : val.t);
+ v.latinOrIntValue = compressed;
+ v.latinKey = false;
+ v.value = QJsonPrivate::Value::valueToStore(val, valueOffset);
+ if (valueSize)
+ QJsonPrivate::Value::copyData(val, (char *)a + valueOffset, compressed);
+}
+
+/*!
+ \fn QJsonArray::iterator QJsonArray::insert(iterator before, const QJsonValue &value)
+
+ Inserts \a value before the position pointed to by \a before, and returns an iterator
+ pointing to the newly inserted item.
+
+ \sa erase(), insert()
+*/
+
+/*!
+ \fn QJsonArray::iterator QJsonArray::erase(iterator it)
+
+ Removes the item pointed to by \a it, and returns an iterator pointing to the
+ next item.
+
+ \sa removeAt()
+*/
+
+/*!
+ Replaces the item at index position \a i with \a value. \a i must
+ be a valid index position in the array (i.e., \c{0 <= i < size()}).
+
+ \sa operator[](), removeAt()
+ */
+void QJsonArray::replace(int i, const QJsonValue &value)
+{
+ Q_ASSERT (a && i >= 0 && i < (int)(a->length));
+ QJsonValue val = value;
+
+ bool compressed;
+ int valueSize = QJsonPrivate::Value::requiredStorage(val, &compressed);
+
+ if (!detach2(valueSize))
+ return;
+
+ if (!a->length)
+ a->tableOffset = sizeof(QJsonPrivate::Array);
+
+ int valueOffset = a->reserveSpace(valueSize, i, 1, true);
+ if (!valueOffset)
+ return;
+
+ QJsonPrivate::Value &v = (*a)[i];
+ v.type = (val.t == QJsonValue::Undefined ? QJsonValue::Null : val.t);
+ v.latinOrIntValue = compressed;
+ v.latinKey = false;
+ v.value = QJsonPrivate::Value::valueToStore(val, valueOffset);
+ if (valueSize)
+ QJsonPrivate::Value::copyData(val, (char *)a + valueOffset, compressed);
+
+ ++d->compactionCounter;
+ if (d->compactionCounter > 32u && d->compactionCounter >= unsigned(a->length) / 2u)
+ compact();
+}
+
+/*!
+ Returns \c true if the array contains an occurrence of \a value, otherwise \c false.
+
+ \sa count()
+ */
+bool QJsonArray::contains(const QJsonValue &value) const
+{
+ for (int i = 0; i < size(); i++) {
+ if (at(i) == value)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns the value at index position \a i as a modifiable reference.
+ \a i must be a valid index position in the array (i.e., \c{0 <= i <
+ size()}).
+
+ The return value is of type QJsonValueRef, a helper class for QJsonArray
+ and QJsonObject. When you get an object of type QJsonValueRef, you can
+ use it as if it were a reference to a QJsonValue. If you assign to it,
+ the assignment will apply to the character in the QJsonArray of QJsonObject
+ from which you got the reference.
+
+ \sa at()
+ */
+QJsonValueRef QJsonArray::operator [](int i)
+{
+ Q_ASSERT(a && i >= 0 && i < (int)a->length);
+ return QJsonValueRef(this, i);
+}
+
+/*!
+ \overload
+
+ Same as at().
+ */
+QJsonValue QJsonArray::operator[](int i) const
+{
+ return at(i);
+}
+
+/*!
+ Returns \c true if this array is equal to \a other.
+ */
+bool QJsonArray::operator==(const QJsonArray &other) const
+{
+ if (a == other.a)
+ return true;
+
+ if (!a)
+ return !other.a->length;
+ if (!other.a)
+ return !a->length;
+ if (a->length != other.a->length)
+ return false;
+
+ for (int i = 0; i < (int)a->length; ++i) {
+ if (QJsonValue(d, a, a->at(i)) != QJsonValue(other.d, other.a, other.a->at(i)))
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Returns \c true if this array is not equal to \a other.
+ */
+bool QJsonArray::operator!=(const QJsonArray &other) const
+{
+ return !(*this == other);
+}
+
+/*! \fn QJsonArray::iterator QJsonArray::begin()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
+ the array.
+
+ \sa constBegin(), end()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::begin() const
+
+ \overload
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::constBegin() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
+ in the array.
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::end()
+
+ Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
+ after the last item in the array.
+
+ \sa begin(), constEnd()
+*/
+
+/*! \fn const_iterator QJsonArray::end() const
+
+ \overload
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::constEnd() const
+
+ Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
+ item after the last item in the array.
+
+ \sa constBegin(), end()
+*/
+
+/*! \fn void QJsonArray::push_back(const QJsonValue &value)
+
+ This function is provided for STL compatibility. It is equivalent
+ to \l{QJsonArray::append()}{append(value)} and will append \a value to the array.
+*/
+
+/*! \fn void QJsonArray::push_front(const QJsonValue &value)
+
+ This function is provided for STL compatibility. It is equivalent
+ to \l{QJsonArray::prepend()}{prepend(value)} and will prepend \a value to the array.
+*/
+
+/*! \fn void QJsonArray::pop_front()
+
+ This function is provided for STL compatibility. It is equivalent
+ to removeFirst(). The array must not be empty. If the array can be
+ empty, call isEmpty() before calling this function.
+*/
+
+/*! \fn void QJsonArray::pop_back()
+
+ This function is provided for STL compatibility. It is equivalent
+ to removeLast(). The array must not be empty. If the array can be
+ empty, call isEmpty() before calling this function.
+*/
+
+/*! \fn bool QJsonArray::empty() const
+
+ This function is provided for STL compatibility. It is equivalent
+ to isEmpty() and returns \c true if the array is empty.
+*/
+
+/*! \class QJsonArray::iterator
+ \inmodule QtCore
+ \brief The QJsonArray::iterator class provides an STL-style non-const iterator for QJsonArray.
+
+ QJsonArray::iterator allows you to iterate over a QJsonArray
+ and to modify the array item associated with the
+ iterator. If you want to iterate over a const QJsonArray, use
+ QJsonArray::const_iterator instead. It is generally a good practice to
+ use QJsonArray::const_iterator on a non-const QJsonArray as well, unless
+ you need to change the QJsonArray through the iterator. Const
+ iterators are slightly faster and improves code readability.
+
+ The default QJsonArray::iterator constructor creates an uninitialized
+ iterator. You must initialize it using a QJsonArray function like
+ QJsonArray::begin(), QJsonArray::end(), or QJsonArray::insert() before you can
+ start iterating.
+
+ Most QJsonArray functions accept an integer index rather than an
+ iterator. For that reason, iterators are rarely useful in
+ connection with QJsonArray. One place where STL-style iterators do
+ make sense is as arguments to \l{generic algorithms}.
+
+ Multiple iterators can be used on the same array. However, be
+ aware that any non-const function call performed on the QJsonArray
+ will render all existing iterators undefined.
+
+ \sa QJsonArray::const_iterator
+*/
+
+/*! \typedef QJsonArray::iterator::iterator_category
+
+ A synonym for \e {std::random_access_iterator_tag} indicating
+ this iterator is a random access iterator.
+*/
+
+/*! \typedef QJsonArray::iterator::difference_type
+
+ \internal
+*/
+
+/*! \typedef QJsonArray::iterator::value_type
+
+ \internal
+*/
+
+/*! \typedef QJsonArray::iterator::reference
+
+ \internal
+*/
+
+/*! \typedef QJsonArray::iterator::pointer
+
+ \internal
+*/
+
+/*! \fn QJsonArray::iterator::iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like operator*() and operator++() should not be called
+ on an uninitialized iterator. Use operator=() to assign a value
+ to it before using it.
+
+ \sa QJsonArray::begin(), QJsonArray::end()
+*/
+
+/*! \fn QJsonArray::iterator::iterator(QJsonArray *array, int index)
+ \internal
+*/
+
+/*! \fn QJsonValueRef QJsonArray::iterator::operator*() const
+
+
+ Returns a modifiable reference to the current item.
+
+ You can change the value of an item by using operator*() on the
+ left side of an assignment.
+
+ The return value is of type QJsonValueRef, a helper class for QJsonArray
+ and QJsonObject. When you get an object of type QJsonValueRef, you can
+ use it as if it were a reference to a QJsonValue. If you assign to it,
+ the assignment will apply to the character in the QJsonArray of QJsonObject
+ from which you got the reference.
+*/
+
+/*! \fn QJsonValueRef *QJsonArray::iterator::operator->() const
+
+ Returns a pointer to a modifiable reference to the current item.
+*/
+
+/*! \fn QJsonValueRef QJsonArray::iterator::operator[](int j) const
+
+ Returns a modifiable reference to the item at offset \a j from the
+ item pointed to by this iterator (the item at position \c{*this + j}).
+
+ This function is provided to make QJsonArray iterators behave like C++
+ pointers.
+
+ The return value is of type QJsonValueRef, a helper class for QJsonArray
+ and QJsonObject. When you get an object of type QJsonValueRef, you can
+ use it as if it were a reference to a QJsonValue. If you assign to it,
+ the assignment will apply to the character in the QJsonArray of QJsonObject
+ from which you got the reference.
+
+ \sa operator+()
+*/
+
+/*!
+ \fn bool QJsonArray::iterator::operator==(const iterator &other) const
+ \fn bool QJsonArray::iterator::operator==(const const_iterator &other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*!
+ \fn bool QJsonArray::iterator::operator!=(const iterator &other) const
+ \fn bool QJsonArray::iterator::operator!=(const const_iterator &other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool QJsonArray::iterator::operator<(const iterator& other) const
+ \fn bool QJsonArray::iterator::operator<(const const_iterator& other) const
+
+ Returns \c true if the item pointed to by this iterator is less than
+ the item pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QJsonArray::iterator::operator<=(const iterator& other) const
+ \fn bool QJsonArray::iterator::operator<=(const const_iterator& other) const
+
+ Returns \c true if the item pointed to by this iterator is less than
+ or equal to the item pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QJsonArray::iterator::operator>(const iterator& other) const
+ \fn bool QJsonArray::iterator::operator>(const const_iterator& other) const
+
+ Returns \c true if the item pointed to by this iterator is greater
+ than the item pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QJsonArray::iterator::operator>=(const iterator& other) const
+ \fn bool QJsonArray::iterator::operator>=(const const_iterator& other) const
+
+ Returns \c true if the item pointed to by this iterator is greater
+ than or equal to the item pointed to by the \a other iterator.
+*/
+
+/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator++()
+
+ The prefix ++ operator, \c{++it}, advances the iterator to the
+ next item in the array and returns an iterator to the new current
+ item.
+
+ Calling this function on QJsonArray::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator, \c{it++}, advances the iterator to the
+ next item in the array and returns an iterator to the previously
+ current item.
+*/
+
+/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator--()
+
+ The prefix -- operator, \c{--it}, makes the preceding item
+ current and returns an iterator to the new current item.
+
+ Calling this function on QJsonArray::begin() leads to undefined results.
+
+ \sa operator++()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::iterator::operator--(int)
+
+ \overload
+
+ The postfix -- operator, \c{it--}, makes the preceding item
+ current and returns an iterator to the previously current item.
+*/
+
+/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator+=(int j)
+
+ Advances the iterator by \a j items. If \a j is negative, the
+ iterator goes backward.
+
+ \sa operator-=(), operator+()
+*/
+
+/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator-=(int j)
+
+ Makes the iterator go back by \a j items. If \a j is negative,
+ the iterator goes forward.
+
+ \sa operator+=(), operator-()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::iterator::operator+(int j) const
+
+ Returns an iterator to the item at \a j positions forward from
+ this iterator. If \a j is negative, the iterator goes backward.
+
+ \sa operator-(), operator+=()
+*/
+
+/*! \fn QJsonArray::iterator QJsonArray::iterator::operator-(int j) const
+
+ Returns an iterator to the item at \a j positions backward from
+ this iterator. If \a j is negative, the iterator goes forward.
+
+ \sa operator+(), operator-=()
+*/
+
+/*! \fn int QJsonArray::iterator::operator-(iterator other) const
+
+ Returns the number of items between the item pointed to by \a
+ other and the item pointed to by this iterator.
+*/
+
+/*! \class QJsonArray::const_iterator
+ \inmodule QtCore
+ \brief The QJsonArray::const_iterator class provides an STL-style const iterator for QJsonArray.
+
+ QJsonArray::const_iterator allows you to iterate over a
+ QJsonArray. If you want to modify the QJsonArray as
+ you iterate over it, use QJsonArray::iterator instead. It is generally a
+ good practice to use QJsonArray::const_iterator on a non-const QJsonArray
+ as well, unless you need to change the QJsonArray through the
+ iterator. Const iterators are slightly faster and improves
+ code readability.
+
+ The default QJsonArray::const_iterator constructor creates an
+ uninitialized iterator. You must initialize it using a QJsonArray
+ function like QJsonArray::constBegin(), QJsonArray::constEnd(), or
+ QJsonArray::insert() before you can start iterating.
+
+ Most QJsonArray functions accept an integer index rather than an
+ iterator. For that reason, iterators are rarely useful in
+ connection with QJsonArray. One place where STL-style iterators do
+ make sense is as arguments to \l{generic algorithms}.
+
+ Multiple iterators can be used on the same array. However, be
+ aware that any non-const function call performed on the QJsonArray
+ will render all existing iterators undefined.
+
+ \sa QJsonArray::iterator
+*/
+
+/*! \fn QJsonArray::const_iterator::const_iterator()
+
+ Constructs an uninitialized iterator.
+
+ Functions like operator*() and operator++() should not be called
+ on an uninitialized iterator. Use operator=() to assign a value
+ to it before using it.
+
+ \sa QJsonArray::constBegin(), QJsonArray::constEnd()
+*/
+
+/*! \fn QJsonArray::const_iterator::const_iterator(const QJsonArray *array, int index)
+ \internal
+*/
+
+/*! \typedef QJsonArray::const_iterator::iterator_category
+
+ A synonym for \e {std::random_access_iterator_tag} indicating
+ this iterator is a random access iterator.
+*/
+
+/*! \typedef QJsonArray::const_iterator::difference_type
+
+ \internal
+*/
+
+/*! \typedef QJsonArray::const_iterator::value_type
+
+ \internal
+*/
+
+/*! \typedef QJsonArray::const_iterator::reference
+
+ \internal
+*/
+
+/*! \typedef QJsonArray::const_iterator::pointer
+
+ \internal
+*/
+
+/*! \fn QJsonArray::const_iterator::const_iterator(const const_iterator &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*! \fn QJsonArray::const_iterator::const_iterator(const iterator &other)
+
+ Constructs a copy of \a other.
+*/
+
+/*! \fn QJsonValue QJsonArray::const_iterator::operator*() const
+
+ Returns the current item.
+*/
+
+/*! \fn QJsonValue *QJsonArray::const_iterator::operator->() const
+
+ Returns a pointer to the current item.
+*/
+
+/*! \fn QJsonValue QJsonArray::const_iterator::operator[](int j) const
+
+ Returns the item at offset \a j from the item pointed to by this iterator (the item at
+ position \c{*this + j}).
+
+ This function is provided to make QJsonArray iterators behave like C++
+ pointers.
+
+ \sa operator+()
+*/
+
+/*! \fn bool QJsonArray::const_iterator::operator==(const const_iterator &other) const
+
+ Returns \c true if \a other points to the same item as this
+ iterator; otherwise returns \c false.
+
+ \sa operator!=()
+*/
+
+/*! \fn bool QJsonArray::const_iterator::operator!=(const const_iterator &other) const
+
+ Returns \c true if \a other points to a different item than this
+ iterator; otherwise returns \c false.
+
+ \sa operator==()
+*/
+
+/*!
+ \fn bool QJsonArray::const_iterator::operator<(const const_iterator& other) const
+
+ Returns \c true if the item pointed to by this iterator is less than
+ the item pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QJsonArray::const_iterator::operator<=(const const_iterator& other) const
+
+ Returns \c true if the item pointed to by this iterator is less than
+ or equal to the item pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QJsonArray::const_iterator::operator>(const const_iterator& other) const
+
+ Returns \c true if the item pointed to by this iterator is greater
+ than the item pointed to by the \a other iterator.
+*/
+
+/*!
+ \fn bool QJsonArray::const_iterator::operator>=(const const_iterator& other) const
+
+ Returns \c true if the item pointed to by this iterator is greater
+ than or equal to the item pointed to by the \a other iterator.
+*/
+
+/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator++()
+
+ The prefix ++ operator, \c{++it}, advances the iterator to the
+ next item in the array and returns an iterator to the new current
+ item.
+
+ Calling this function on QJsonArray::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::const_iterator::operator++(int)
+
+ \overload
+
+ The postfix ++ operator, \c{it++}, advances the iterator to the
+ next item in the array and returns an iterator to the previously
+ current item.
+*/
+
+/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator--()
+
+ The prefix -- operator, \c{--it}, makes the preceding item
+ current and returns an iterator to the new current item.
+
+ Calling this function on QJsonArray::begin() leads to undefined results.
+
+ \sa operator++()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::const_iterator::operator--(int)
+
+ \overload
+
+ The postfix -- operator, \c{it--}, makes the preceding item
+ current and returns an iterator to the previously current item.
+*/
+
+/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator+=(int j)
+
+ Advances the iterator by \a j items. If \a j is negative, the
+ iterator goes backward.
+
+ \sa operator-=(), operator+()
+*/
+
+/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator-=(int j)
+
+ Makes the iterator go back by \a j items. If \a j is negative,
+ the iterator goes forward.
+
+ \sa operator+=(), operator-()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::const_iterator::operator+(int j) const
+
+ Returns an iterator to the item at \a j positions forward from
+ this iterator. If \a j is negative, the iterator goes backward.
+
+ \sa operator-(), operator+=()
+*/
+
+/*! \fn QJsonArray::const_iterator QJsonArray::const_iterator::operator-(int j) const
+
+ Returns an iterator to the item at \a j positions backward from
+ this iterator. If \a j is negative, the iterator goes forward.
+
+ \sa operator+(), operator-=()
+*/
+
+/*! \fn int QJsonArray::const_iterator::operator-(const_iterator other) const
+
+ Returns the number of items between the item pointed to by \a
+ other and the item pointed to by this iterator.
+*/
+
+
+/*!
+ \internal
+ */
+void QJsonArray::detach(uint reserve)
+{
+ Q_UNUSED(reserve)
+ Q_ASSERT(!reserve);
+ detach2(0);
+}
+
+/*!
+ \internal
+ */
+bool QJsonArray::detach2(uint reserve)
+{
+ if (!d) {
+ if (reserve >= QJsonPrivate::Value::MaxSize) {
+ qWarning("QJson: Document too large to store in data structure");
+ return false;
+ }
+ d = new QJsonPrivate::Data(reserve, QJsonValue::Array);
+ a = static_cast<QJsonPrivate::Array *>(d->header->root());
+ d->ref.ref();
+ return true;
+ }
+ if (reserve == 0 && d->ref.load() == 1)
+ return true;
+
+ QJsonPrivate::Data *x = d->clone(a, reserve);
+ if (!x)
+ return false;
+ x->ref.ref();
+ if (!d->ref.deref())
+ delete d;
+ d = x;
+ a = static_cast<QJsonPrivate::Array *>(d->header->root());
+ return true;
+}
+
+/*!
+ \internal
+ */
+void QJsonArray::compact()
+{
+ if (!d || !d->compactionCounter)
+ return;
+
+ detach2();
+ d->compact();
+ a = static_cast<QJsonPrivate::Array *>(d->header->root());
+}
+
+
+#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
+QDebug operator<<(QDebug dbg, const QJsonArray &a)
+{
+ QDebugStateSaver saver(dbg);
+ if (!a.a) {
+ dbg << "QJsonArray()";
+ return dbg;
+ }
+ QByteArray json;
+ QJsonPrivate::Writer::arrayToJson(a.a, json, 0, true);
+ dbg.nospace() << "QJsonArray("
+ << json.constData() // print as utf-8 string without extra quotation marks
+ << ")";
+ return dbg;
+}
+#endif
+
+QT_END_NAMESPACE
+
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index 2336278b17..ca8bd30698 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -200,7 +200,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 4bab0b9f01..a8cabd52e1 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 <private/qjni_p.h>
# include <private/qjnihelpers_p.h>
#endif
@@ -186,7 +186,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(
@@ -816,6 +816,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
@@ -2266,7 +2274,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/<pid>/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/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index bca6918b4a..a3b8be8911 100644
--- a/src/corelib/plugin/qlibrary.cpp
+++ b/src/corelib/plugin/qlibrary.cpp
@@ -239,21 +239,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<char *>(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();
+ }
}
/*
@@ -751,7 +764,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");
}
diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp
index 3c4fbaf348..23b9ad6434 100644
--- a/src/corelib/plugin/qlibrary_unix.cpp
+++ b/src/corelib/plugin/qlibrary_unix.cpp
@@ -44,25 +44,17 @@
#include <qcoreapplication.h>
#include <private/qfilesystementry_p.h>
+#include <dlfcn.h>
+
#ifdef Q_OS_MAC
# include <private/qcore_mac_p.h>
#endif
QT_BEGIN_NAMESPACE
-#if !defined(QT_HPUX_LD)
-QT_BEGIN_INCLUDE_NAMESPACE
-#include <dlfcn.h>
-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());
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index b7c3bc1287..d0f83d2b6a 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<void *>(this->end()), static_cast<const void *>(b),
+ (e - b) * sizeof(T));
this->size += e - b;
}
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 4040d59b0a..25f829c38c 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -3855,14 +3855,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<void*>(uc), static_cast<const void *>(d->data() + copystart), size * sizeof(QChar));
uc += size;
- memcpy(uc, after.d->data(), al * sizeof(QChar));
+ memcpy(static_cast<void *>(uc), static_cast<const void *>(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<void *>(uc), static_cast<const void *>(d->data() + copystart), (d->size - copystart) * sizeof(QChar));
newstring.resize(newlen);
*this = newstring;
caretMode = QRegExp::CaretWontMatch;
@@ -6309,7 +6309,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<void *>(uc), static_cast<const void *>(d->data()), sizeof(QChar)*len);
} else {
if (truncate)
result = left(width);
@@ -11834,7 +11834,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
@@ -11854,6 +11854,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
*/
diff --git a/src/corelib/tools/qtimezone.cpp b/src/corelib/tools/qtimezone.cpp
index 6a514abbfe..65c304bcf7 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 ca36f9d297..4d357111f2 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 <qt_windows.h>
#endif // Q_OS_WIN
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
#include <QtCore/private/qjni_p.h>
#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;
@@ -442,7 +442,7 @@ private:
};
#endif // Q_OS_WIN
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
class QAndroidTimeZonePrivate final : public QTimeZonePrivate
{
public:
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index b2f05452ae..d0088471c7 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -344,7 +344,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, in
while (s < asize)
new (ptr+(s++)) T(*abuf++);
} else {
- memcpy(&ptr[s], abuf, increment * sizeof(T));
+ memcpy(static_cast<void *>(&ptr[s]), static_cast<const void *>(abuf), increment * sizeof(T));
s = asize;
}
}
@@ -392,7 +392,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int a
QT_RETHROW;
}
} else {
- memcpy(ptr, oldPtr, copySize * sizeof(T));
+ memcpy(static_cast<void *>(ptr), static_cast<const void *>(oldPtr), copySize * sizeof(T));
}
}
s = copySize;
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 24a19e68d4..9a6e67cc0b 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -747,7 +747,7 @@ typename QVector<T>::iterator QVector<T>::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<void *>(i), static_cast<const void *>(b), (d->size - offset) * sizeof(T));
while (i != b)
new (--i) T(copy);
}
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index 56b30279bd..72224f280d 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -161,7 +161,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/corelib/xml/qxmlstream_p.h b/src/corelib/xml/qxmlstream_p.h
new file mode 100644
index 0000000000..e6c89e40cd
--- /dev/null
+++ b/src/corelib/xml/qxmlstream_p.h
@@ -0,0 +1,1966 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore 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$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+
+// This file was generated by qlalr - DO NOT EDIT!
+#ifndef QXMLSTREAM_P_H
+#define QXMLSTREAM_P_H
+
+#if defined(ERROR)
+# undef ERROR
+#endif
+
+class QXmlStreamReader_Table
+{
+public:
+ enum VariousConstants {
+ EOF_SYMBOL = 0,
+ AMPERSAND = 5,
+ ANY = 41,
+ ATTLIST = 31,
+ BANG = 25,
+ CDATA = 47,
+ CDATA_START = 28,
+ COLON = 17,
+ COMMA = 19,
+ DASH = 20,
+ DBLQUOTE = 8,
+ DIGIT = 27,
+ DOCTYPE = 29,
+ DOT = 23,
+ ELEMENT = 30,
+ EMPTY = 40,
+ ENTITIES = 51,
+ ENTITY = 32,
+ ENTITY_DONE = 45,
+ EQ = 14,
+ ERROR = 43,
+ FIXED = 39,
+ HASH = 6,
+ ID = 48,
+ IDREF = 49,
+ IDREFS = 50,
+ IMPLIED = 38,
+ LANGLE = 3,
+ LBRACK = 9,
+ LETTER = 26,
+ LPAREN = 11,
+ NDATA = 36,
+ NMTOKEN = 52,
+ NMTOKENS = 53,
+ NOTATION = 33,
+ NOTOKEN = 1,
+ PARSE_ENTITY = 44,
+ PCDATA = 42,
+ PERCENT = 15,
+ PIPE = 13,
+ PLUS = 21,
+ PUBLIC = 35,
+ QUESTIONMARK = 24,
+ QUOTE = 7,
+ RANGLE = 4,
+ RBRACK = 10,
+ REQUIRED = 37,
+ RPAREN = 12,
+ SEMICOLON = 18,
+ SHIFT_THERE = 56,
+ SLASH = 16,
+ SPACE = 2,
+ STAR = 22,
+ SYSTEM = 34,
+ UNRESOLVED_ENTITY = 46,
+ VERSION = 55,
+ XML = 54,
+
+ ACCEPT_STATE = 416,
+ RULE_COUNT = 270,
+ STATE_COUNT = 427,
+ TERMINAL_COUNT = 57,
+ NON_TERMINAL_COUNT = 84,
+
+ GOTO_INDEX_OFFSET = 427,
+ GOTO_INFO_OFFSET = 1017,
+ GOTO_CHECK_OFFSET = 1017
+ };
+
+ static const char *const spell [];
+ static const short lhs [];
+ static const short rhs [];
+ static const short goto_default [];
+ static const short action_default [];
+ static const short action_index [];
+ static const short action_info [];
+ static const short action_check [];
+
+ static inline int nt_action (int state, int nt)
+ {
+ const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
+ if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
+ return goto_default [nt];
+
+ return action_info [GOTO_INFO_OFFSET + yyn];
+ }
+
+ static inline int t_action (int state, int token)
+ {
+ const int yyn = action_index [state] + token;
+
+ if (yyn < 0 || action_check [yyn] != token)
+ return - action_default [state];
+
+ return action_info [yyn];
+ }
+};
+
+
+const char *const QXmlStreamReader_Table::spell [] = {
+ "end of file", 0, " ", "<", ">", "&", "#", "\'", "\"", "[",
+ "]", "(", ")", "|", "=", "%", "/", ":", ";", ",",
+ "-", "+", "*", ".", "?", "!", "[a-zA-Z]", "[0-9]", "[CDATA[", "DOCTYPE",
+ "ELEMENT", "ATTLIST", "ENTITY", "NOTATION", "SYSTEM", "PUBLIC", "NDATA", "REQUIRED", "IMPLIED", "FIXED",
+ "EMPTY", "ANY", "PCDATA", 0, 0, 0, 0, "CDATA", "ID", "IDREF",
+ "IDREFS", "ENTITIES", "NMTOKEN", "NMTOKENS", "<?xml", "version", 0};
+
+const short QXmlStreamReader_Table::lhs [] = {
+ 57, 57, 59, 59, 59, 59, 59, 59, 59, 59,
+ 67, 68, 64, 72, 72, 72, 75, 66, 66, 66,
+ 66, 79, 78, 80, 80, 80, 80, 80, 80, 80,
+ 81, 81, 81, 81, 81, 81, 81, 87, 83, 88,
+ 88, 88, 88, 91, 92, 93, 93, 93, 93, 94,
+ 94, 96, 96, 96, 97, 97, 98, 98, 99, 99,
+ 100, 100, 89, 89, 95, 90, 101, 101, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 104, 105,
+ 105, 105, 105, 107, 108, 109, 109, 84, 84, 110,
+ 110, 112, 112, 85, 85, 85, 65, 65, 76, 114,
+ 63, 115, 116, 86, 86, 86, 117, 117, 117, 117,
+ 117, 117, 117, 117, 117, 117, 117, 117, 117, 117,
+ 117, 117, 117, 117, 117, 117, 117, 117, 117, 118,
+ 118, 119, 119, 119, 119, 119, 119, 119, 119, 122,
+ 70, 70, 70, 70, 123, 124, 123, 124, 123, 124,
+ 123, 124, 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 125, 73, 113, 113, 113, 113,
+ 127, 128, 127, 128, 127, 128, 127, 128, 129, 129,
+ 129, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+ 129, 129, 129, 129, 129, 129, 129, 129, 129, 129,
+ 129, 129, 129, 106, 106, 106, 106, 131, 132, 131,
+ 132, 131, 131, 132, 132, 133, 133, 133, 133, 135,
+ 71, 71, 71, 136, 136, 137, 62, 60, 61, 138,
+ 121, 82, 130, 134, 120, 139, 139, 139, 139, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 74,
+ 69, 69, 77, 111, 102, 102, 102, 102, 102, 140};
+
+const short QXmlStreamReader_Table::rhs [] = {
+ 2, 1, 4, 2, 2, 2, 2, 2, 2, 0,
+ 1, 1, 9, 2, 4, 0, 4, 4, 6, 6,
+ 4, 1, 3, 1, 1, 1, 2, 2, 2, 0,
+ 1, 1, 1, 1, 1, 1, 1, 4, 4, 1,
+ 1, 1, 1, 1, 2, 1, 1, 1, 0, 2,
+ 2, 2, 6, 6, 1, 5, 1, 5, 3, 5,
+ 0, 1, 6, 8, 4, 2, 1, 5, 1, 1,
+ 1, 1, 1, 1, 1, 1, 6, 7, 1, 2,
+ 2, 1, 4, 3, 3, 1, 2, 5, 6, 4,
+ 6, 3, 5, 5, 3, 4, 4, 5, 2, 3,
+ 2, 2, 4, 5, 5, 7, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 1, 1, 1, 1, 1,
+ 2, 2, 3, 3, 2, 2, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 3, 3,
+ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 3, 3, 2, 2, 2,
+ 2, 1, 1, 1, 1, 1, 1, 1, 1, 5,
+ 0, 1, 3, 1, 3, 2, 4, 3, 5, 1,
+ 3, 3, 3, 3, 4, 1, 1, 2, 2, 2,
+ 4, 2, 2, 2, 2, 2, 2, 2, 0, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 2};
+
+const short QXmlStreamReader_Table::action_default [] = {
+ 10, 259, 0, 2, 1, 0, 125, 117, 119, 120,
+ 127, 129, 123, 11, 114, 108, 0, 109, 128, 111,
+ 115, 113, 121, 124, 126, 107, 110, 112, 118, 116,
+ 131, 122, 240, 12, 254, 136, 250, 253, 0, 130,
+ 140, 257, 16, 252, 138, 137, 0, 256, 139, 259,
+ 231, 258, 255, 0, 0, 264, 0, 247, 246, 0,
+ 249, 248, 245, 241, 99, 263, 0, 236, 0, 0,
+ 260, 97, 98, 101, 0, 132, 134, 133, 135, 0,
+ 0, 261, 0, 0, 176, 0, 173, 165, 167, 168,
+ 142, 154, 171, 162, 156, 157, 153, 159, 163, 161,
+ 169, 172, 152, 155, 158, 160, 166, 164, 174, 170,
+ 150, 175, 0, 144, 148, 146, 151, 141, 149, 0,
+ 147, 143, 145, 0, 15, 14, 262, 0, 22, 21,
+ 261, 30, 0, 20, 0, 0, 32, 37, 31, 0,
+ 33, 261, 0, 34, 0, 24, 0, 35, 0, 26,
+ 36, 25, 0, 242, 41, 40, 261, 43, 49, 261,
+ 42, 0, 44, 261, 49, 261, 0, 261, 0, 49,
+ 0, 48, 46, 47, 51, 52, 261, 261, 0, 57,
+ 261, 54, 261, 0, 58, 0, 55, 261, 53, 261,
+ 0, 56, 65, 0, 261, 61, 261, 0, 59, 62,
+ 63, 0, 261, 0, 0, 60, 64, 45, 50, 66,
+ 0, 39, 0, 0, 261, 0, 94, 95, 0, 0,
+ 0, 0, 261, 0, 210, 201, 203, 205, 178, 190,
+ 208, 199, 193, 191, 194, 189, 196, 198, 206, 209,
+ 188, 192, 195, 197, 202, 200, 204, 207, 211, 213,
+ 212, 186, 0, 0, 243, 180, 184, 182, 0, 0,
+ 93, 187, 177, 185, 0, 183, 179, 181, 92, 0,
+ 96, 0, 0, 0, 0, 0, 261, 86, 261, 0,
+ 262, 0, 87, 0, 89, 69, 74, 73, 70, 71,
+ 72, 261, 75, 76, 0, 0, 0, 269, 268, 266,
+ 267, 265, 67, 261, 0, 261, 0, 0, 68, 77,
+ 261, 0, 261, 0, 0, 78, 0, 79, 0, 82,
+ 85, 0, 0, 215, 225, 224, 0, 227, 229, 228,
+ 226, 0, 244, 217, 221, 219, 223, 214, 222, 0,
+ 220, 216, 218, 0, 81, 80, 0, 83, 0, 84,
+ 88, 100, 0, 38, 0, 0, 0, 0, 91, 90,
+ 0, 103, 23, 27, 29, 28, 0, 0, 261, 262,
+ 0, 261, 0, 106, 105, 261, 0, 104, 102, 0,
+ 0, 18, 261, 17, 0, 19, 0, 0, 251, 0,
+ 261, 0, 239, 0, 232, 238, 0, 237, 234, 261,
+ 261, 262, 233, 235, 0, 261, 0, 230, 261, 0,
+ 261, 0, 231, 0, 0, 13, 270, 9, 5, 8,
+ 4, 0, 7, 259, 6, 0, 3};
+
+const short QXmlStreamReader_Table::goto_default [] = {
+ 2, 4, 3, 49, 388, 43, 37, 52, 47, 41,
+ 249, 53, 127, 84, 393, 81, 85, 126, 42, 46,
+ 169, 130, 131, 146, 145, 149, 138, 136, 140, 147,
+ 139, 159, 160, 157, 168, 167, 209, 165, 164, 166,
+ 187, 180, 196, 200, 303, 302, 295, 321, 320, 319,
+ 279, 277, 278, 142, 56, 141, 222, 38, 34, 148,
+ 39, 48, 40, 248, 45, 36, 119, 112, 330, 111,
+ 264, 252, 251, 250, 339, 326, 325, 329, 398, 399,
+ 50, 51, 59, 0};
+
+const short QXmlStreamReader_Table::action_index [] = {
+ -21, -57, 33, 119, 960, 70, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, 105, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, 40, -57,
+ 795, -57, 47, -57, -57, -57, 107, -57, -57, -57,
+ 84, -57, -57, -38, 80, -57, 12, -57, -57, 97,
+ -57, -57, -57, -57, -57, -57, 13, -57, 56, 34,
+ -57, -57, -57, -57, 51, -57, -57, -57, -57, 53,
+ 57, 84, 300, 255, -57, 84, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, 355, -57, -57, -57, -57, -57, -57, 326,
+ -57, -57, -57, 48, -57, -57, -57, 50, -57, -57,
+ 84, 155, 32, -57, 38, 22, -57, -57, -57, 115,
+ -57, 35, 156, -57, 173, -57, 245, -57, 44, -57,
+ -57, -57, 16, -57, -57, -57, 29, -57, 116, 29,
+ -57, 133, -57, 29, 129, 84, 15, 29, -22, 121,
+ 74, -57, -57, -57, -57, 82, 29, 29, 88, -57,
+ 29, 7, 29, 86, -57, 83, -57, 27, 19, 26,
+ 94, -57, -57, 106, 29, 3, 29, -8, -57, -57,
+ -57, 104, 29, -6, -7, -57, -57, -57, -57, -57,
+ 17, -57, -2, 11, 29, 18, -57, -57, 850, 65,
+ 465, 67, 84, 135, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, -57, 630, 24, -57, -57, -57, -57, 84, 76,
+ -57, -57, -57, -57, 740, -57, -57, -57, -57, 39,
+ -57, 23, 21, 14, 78, 22, 84, -57, 84, 184,
+ 20, 31, -57, 41, -57, -57, -57, -57, -57, -57,
+ -57, 84, -57, -57, 36, 126, 162, -57, -57, -57,
+ -57, -57, -57, 29, 79, 29, 29, 160, -57, -57,
+ 29, 145, 29, 75, 29, -57, 575, -57, 410, -57,
+ -57, 110, 64, -57, -57, -57, 685, -57, -57, -57,
+ -57, -17, -57, -57, -57, -57, -57, -57, -57, 520,
+ -57, -57, -57, 29, -57, -57, 61, -57, 29, -57,
+ -57, -57, 29, -57, 29, 29, -15, 29, -57, -57,
+ 29, -57, -57, -57, -57, -57, 95, 43, 29, 45,
+ 9, 29, 10, -57, -57, 29, 2, -57, -57, -24,
+ 190, -57, 29, -57, 1, -57, 905, 150, -57, -26,
+ 29, 0, -57, 109, -26, -57, 8, -57, -57, 29,
+ 29, -19, -57, -57, -11, 29, 59, -57, 29, -5,
+ 29, 103, 29, -16, 6, -57, -57, -57, -57, -57,
+ -57, 69, -57, -57, -57, 905, -57,
+
+ -84, -84, -84, 204, 75, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, 7, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ 101, -84, -84, -84, -84, -84, -84, -84, -84, 64,
+ 54, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, 68, -84, 30, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ 32, -84, -16, -7, -84, 42, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, 45, -84, -84, -84, -84, -84, -84, 44,
+ -84, -84, -84, 33, -84, -84, -84, -84, -84, -84,
+ 36, 108, -84, -84, -84, 69, -84, -84, -84, 62,
+ -84, 63, -84, -84, -84, -84, 118, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -2, -84, -84, -10,
+ -84, -84, -84, 25, -21, 11, -84, 20, -84, -25,
+ -84, -84, -84, -84, -84, -84, 1, 2, -36, -84,
+ -9, -84, 5, -13, -84, -8, -84, 6, -84, 8,
+ 12, -84, -84, -84, 23, -84, 4, -1, -84, -84,
+ -84, -84, 0, -84, -14, -84, -84, -84, -84, -84,
+ -84, -84, 55, -84, 58, -84, -84, -84, -84, 53,
+ 47, 123, 67, 66, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -15, -84, -84, -84, -84, -84, 41, 40,
+ -84, -84, -84, -84, -46, -84, -84, -84, -84, -84,
+ -84, 35, -84, 34, 37, 18, 70, -84, 89, -84,
+ 43, -84, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, 48, -84, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, 31, -84, 29, 27, 17, -84, -84,
+ 38, 24, 39, -84, 49, -84, 71, -84, 93, -84,
+ -84, -84, -12, -84, -84, -84, 94, -84, -84, -84,
+ -84, -84, -84, -84, -84, -84, -84, -84, -84, 78,
+ -84, -84, -84, 50, -84, -84, 46, -84, 56, -84,
+ -84, -84, 60, -84, 61, 59, 51, 57, -84, -84,
+ 14, -84, -84, -84, -84, -84, -11, -6, 72, -5,
+ -84, -3, -84, -84, -84, 52, -84, -84, -84, -20,
+ 77, -84, 21, -84, -84, -84, 76, 16, -84, 19,
+ 26, -84, -84, -84, 10, -84, -84, -84, -84, 80,
+ 13, 73, -84, -84, -84, 22, -27, -84, 9, -84,
+ 28, 15, 82, -84, -84, -84, -84, -84, -84, -84,
+ -84, -84, -84, 3, -84, 98, -84};
+
+const short QXmlStreamReader_Table::action_info [] = {
+ 65, 332, 65, 405, 392, 385, 377, 65, 414, 410,
+ 415, 55, 397, 374, 373, 217, 206, 408, 65, 65,
+ 207, 211, 216, 1, 55, 199, 182, 192, 70, 70,
+ 63, 70, 189, 416, 153, 350, 133, 70, 72, 55,
+ 65, 351, 254, 270, 73, 284, 65, 310, 55, 65,
+ 83, 82, 83, 82, 129, 83, 82, 54, 70, 128,
+ 83, 82, 66, 64, 83, 82, 318, 316, 318, 316,
+ 54, 212, 83, 82, 83, 82, 54, 55, 367, 366,
+ 69, 80, 79, 83, 82, 163, 70, 314, 305, 272,
+ 55, 306, 305, 354, 163, 177, 55, 163, 379, 163,
+ 65, 176, 83, 82, 55, 163, 58, 57, 0, 65,
+ 83, 82, 65, 395, 65, 62, 203, 202, 195, 194,
+ 65, 417, 16, 61, 60, 396, 156, 272, 0, 66,
+ 64, 65, 317, 318, 316, 378, 379, 171, 173, 162,
+ 172, 54, 171, 173, 163, 172, 0, 345, 344, 343,
+ 171, 173, 0, 172, 0, 155, 154, 70, 134, 65,
+ 0, 55, 297, 220, 218, 298, 389, 0, 300, 0,
+ 135, 301, 299, 33, 66, 64, 65, 297, 0, 297,
+ 298, 0, 298, 300, 0, 300, 301, 299, 301, 299,
+ 221, 219, 70, 272, 381, 291, 0, 0, 0, 128,
+ 13, 0, 0, 273, 271, 274, 275, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 287, 294, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 285, 288, 289, 290, 286, 292, 293, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 70, 134, 0,
+ 0, 0, 0, 0, 0, 362, 0, 108, 0, 103,
+ 135, 94, 117, 116, 95, 104, 97, 105, 99, 93,
+ 98, 107, 87, 106, 88, 89, 100, 109, 92, 101,
+ 86, 96, 91, 0, 0, 0, 0, 0, 0, 0,
+ 13, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 108, 0, 103, 0, 94, 102, 90, 95,
+ 104, 97, 105, 99, 93, 98, 107, 87, 106, 88,
+ 89, 100, 109, 92, 101, 86, 96, 91, 108, 0,
+ 103, 0, 94, 121, 120, 95, 104, 97, 105, 99,
+ 93, 98, 107, 87, 106, 88, 89, 100, 109, 92,
+ 101, 86, 96, 91, 0, 0, 0, 108, 0, 103,
+ 0, 94, 114, 113, 95, 104, 97, 105, 99, 93,
+ 98, 107, 87, 106, 88, 89, 100, 109, 92, 101,
+ 86, 96, 91, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 108, 0, 103, 322, 94, 337, 336, 95,
+ 104, 97, 105, 99, 93, 98, 107, 87, 106, 88,
+ 89, 100, 109, 92, 101, 86, 96, 91, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 246, 233, 241,
+ 223, 232, 262, 261, 234, 242, 236, 243, 237, 231,
+ 0, 245, 225, 244, 226, 227, 238, 247, 230, 239,
+ 224, 235, 229, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 13, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 108, 0, 103, 322, 94, 341, 340, 95,
+ 104, 97, 105, 99, 93, 98, 107, 87, 106, 88,
+ 89, 100, 109, 92, 101, 86, 96, 91, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 108, 0, 103,
+ 322, 94, 324, 323, 95, 104, 97, 105, 99, 93,
+ 98, 107, 87, 106, 88, 89, 100, 109, 92, 101,
+ 86, 96, 91, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 13, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 246, 233, 241, 223, 232, 256, 255, 234,
+ 242, 236, 243, 237, 231, 0, 245, 225, 244, 226,
+ 227, 238, 247, 230, 239, 224, 235, 229, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 108, 0, 103,
+ 322, 94, 334, 333, 95, 104, 97, 105, 99, 93,
+ 98, 107, 87, 106, 88, 89, 100, 109, 92, 101,
+ 86, 96, 91, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 13, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 246, 233, 241, 223, 232, 266, 265, 234,
+ 242, 236, 243, 237, 231, 0, 245, 225, 244, 226,
+ 227, 238, 247, 230, 239, 224, 235, 229, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 30, 0, 25,
+ 74, 15, 24, 10, 17, 26, 19, 27, 21, 14,
+ 20, 29, 7, 28, 8, 9, 22, 31, 12, 23,
+ 6, 18, 11, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 13, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 246, 233, 241, 223, 232, 240, 228, 234,
+ 242, 236, 243, 237, 231, 0, 245, 225, 244, 226,
+ 227, 238, 247, 230, 239, 224, 235, 229, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 30, 387, 25,
+ 5, 15, 24, 10, 17, 26, 19, 27, 21, 14,
+ 20, 29, 7, 28, 8, 9, 22, 31, 12, 23,
+ 6, 18, 11, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 13, 32, 0, 0, 0, 0, 0, 0, 0, 33,
+ 0, 0, 30, 16, 25, 5, 15, 24, 10, 17,
+ 26, 19, 27, 21, 14, 20, 29, 7, 28, 8,
+ 9, 22, 31, 12, 23, 6, 18, 11, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 13, 32, 0, 0, 0,
+ 0, 0, 0, 0, 33, 0, 0,
+
+ 380, 179, 210, 181, 425, 368, 205, 375, 371, 372,
+ 161, 208, 204, 178, 185, 174, 201, 183, 188, 198,
+ 190, 409, 407, 175, 184, 404, 267, 67, 412, 186,
+ 400, 361, 193, 384, 406, 197, 67, 170, 391, 390,
+ 411, 307, 331, 304, 309, 125, 124, 71, 132, 191,
+ 311, 313, 110, 260, 352, 276, 0, 257, 259, 123,
+ 296, 118, 308, 348, 376, 386, 315, 346, 312, 258,
+ 215, 394, 360, 349, 358, 213, 359, 353, 356, 269,
+ 0, 328, 281, 0, 370, 44, 44, 280, 328, 369,
+ 0, 355, 402, 400, 383, 347, 413, 401, 382, 394,
+ 158, 283, 426, 328, 328, 357, 280, 0, 44, 214,
+ 0, 76, 122, 115, 137, 0, 150, 0, 143, 263,
+ 253, 0, 68, 152, 137, 151, 150, 144, 143, 0,
+ 0, 0, 0, 0, 327, 365, 268, 144, 35, 35,
+ 282, 327, 363, 364, 0, 0, 0, 0, 0, 0,
+ 0, 403, 0, 0, 342, 0, 327, 327, 0, 0,
+ 0, 35, 78, 0, 75, 77, 0, 0, 0, 338,
+ 335, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 423, 0, 420,
+ 418, 424, 422, 419, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 421, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0};
+
+const short QXmlStreamReader_Table::action_check [] = {
+ 26, 18, 26, 14, 4, 4, 4, 26, 24, 14,
+ 4, 26, 4, 4, 4, 4, 22, 55, 26, 26,
+ 42, 4, 4, 44, 26, 22, 19, 12, 2, 2,
+ 18, 2, 13, 0, 18, 4, 4, 2, 4, 26,
+ 26, 20, 18, 4, 4, 4, 26, 11, 26, 26,
+ 7, 8, 7, 8, 4, 7, 8, 6, 2, 9,
+ 7, 8, 24, 25, 7, 8, 7, 8, 7, 8,
+ 6, 36, 7, 8, 7, 8, 6, 26, 34, 35,
+ 24, 34, 35, 7, 8, 11, 2, 12, 13, 20,
+ 26, 12, 13, 15, 11, 13, 26, 11, 29, 11,
+ 26, 19, 7, 8, 26, 11, 26, 27, -1, 26,
+ 7, 8, 26, 4, 26, 18, 12, 13, 12, 13,
+ 26, 2, 3, 26, 27, 16, 11, 20, -1, 24,
+ 25, 26, 6, 7, 8, 28, 29, 21, 22, 6,
+ 24, 6, 21, 22, 11, 24, -1, 37, 38, 39,
+ 21, 22, -1, 24, -1, 40, 41, 2, 3, 26,
+ -1, 26, 17, 7, 8, 20, 16, -1, 23, -1,
+ 15, 26, 27, 54, 24, 25, 26, 17, -1, 17,
+ 20, -1, 20, 23, -1, 23, 26, 27, 26, 27,
+ 34, 35, 2, 20, 4, 11, -1, -1, -1, 9,
+ 45, -1, -1, 30, 31, 32, 33, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 32, 33, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 47, 48, 49, 50, 51, 52, 53, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 2, 3, -1,
+ -1, -1, -1, -1, -1, 10, -1, 2, -1, 4,
+ 15, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, -1, -1, -1, -1, -1, -1, -1,
+ 45, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 2, -1, 4, -1, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 2, -1,
+ 4, -1, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, -1, -1, -1, 2, -1, 4,
+ -1, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 2, -1, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 45, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ -1, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 45, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 2, -1, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 45, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 2, -1, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 45, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, -1, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 45, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 2, -1, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 45, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, -1, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 45, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 2, -1, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 45, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, -1, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 45, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 45, 46, -1, -1, -1, -1, -1, -1, -1, 54,
+ -1, -1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 45, 46, -1, -1, -1,
+ -1, -1, -1, -1, 54, -1, -1,
+
+ 20, 37, 12, 12, 1, 16, 20, 13, 13, 12,
+ 12, 36, 12, 12, 12, 36, 12, 12, 12, 20,
+ 12, 12, 49, 12, 37, 12, 72, 20, 13, 37,
+ 20, 17, 12, 12, 12, 12, 20, 12, 12, 20,
+ 12, 12, 54, 12, 17, 13, 13, 17, 12, 37,
+ 12, 12, 68, 13, 20, 20, -1, 72, 17, 17,
+ 12, 68, 45, 20, 12, 1, 17, 17, 44, 16,
+ 12, 17, 54, 17, 17, 12, 17, 17, 17, 12,
+ -1, 10, 12, -1, 12, 10, 10, 17, 10, 17,
+ -1, 54, 12, 20, 17, 49, 14, 17, 21, 17,
+ 38, 12, 4, 10, 10, 54, 17, -1, 10, 54,
+ -1, 10, 68, 68, 6, -1, 8, -1, 10, 72,
+ 54, -1, 54, 54, 6, 17, 8, 19, 10, -1,
+ -1, -1, -1, -1, 63, 17, 13, 19, 63, 63,
+ 51, 63, 24, 25, -1, -1, -1, -1, -1, -1,
+ -1, 78, -1, -1, 76, -1, 63, 63, -1, -1,
+ -1, 63, 61, -1, 63, 64, -1, -1, -1, 76,
+ 76, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 3, -1, 5,
+ 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 19, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1};
+
+
+template <typename T> class QXmlStreamSimpleStack {
+ T *data;
+ int tos, cap;
+public:
+ inline QXmlStreamSimpleStack():data(0), tos(-1), cap(0){}
+ inline ~QXmlStreamSimpleStack(){ if (data) free(data); }
+
+ inline void reserve(int extraCapacity) {
+ if (tos + extraCapacity + 1 > cap) {
+ cap = qMax(tos + extraCapacity + 1, cap << 1 );
+ void *ptr = realloc(static_cast<void *>(data), cap * sizeof(T));
+ data = reinterpret_cast<T *>(ptr);
+ Q_CHECK_PTR(data);
+ }
+ }
+
+ inline T &push() { reserve(1); return data[++tos]; }
+ inline T &rawPush() { return data[++tos]; }
+ inline const T &top() const { return data[tos]; }
+ inline T &top() { return data[tos]; }
+ inline T &pop() { return data[tos--]; }
+ inline T &operator[](int index) { return data[index]; }
+ inline const T &at(int index) const { return data[index]; }
+ inline int size() const { return tos + 1; }
+ inline void resize(int s) { tos = s - 1; }
+ inline bool isEmpty() const { return tos < 0; }
+ inline void clear() { tos = -1; }
+};
+
+
+class QXmlStream
+{
+ Q_DECLARE_TR_FUNCTIONS(QXmlStream)
+};
+
+class QXmlStreamPrivateTagStack {
+public:
+ struct NamespaceDeclaration
+ {
+ QStringRef prefix;
+ QStringRef namespaceUri;
+ };
+
+ struct Tag
+ {
+ QStringRef name;
+ QStringRef qualifiedName;
+ NamespaceDeclaration namespaceDeclaration;
+ int tagStackStringStorageSize;
+ int namespaceDeclarationsSize;
+ };
+
+
+ QXmlStreamPrivateTagStack();
+ QXmlStreamSimpleStack<NamespaceDeclaration> namespaceDeclarations;
+ QString tagStackStringStorage;
+ int tagStackStringStorageSize;
+ int initialTagStackStringStorageSize;
+ bool tagsDone;
+
+ inline QStringRef addToStringStorage(const QStringRef &s) {
+ int pos = tagStackStringStorageSize;
+ int sz = s.size();
+ if (pos != tagStackStringStorage.size())
+ tagStackStringStorage.resize(pos);
+ tagStackStringStorage.insert(pos, s.unicode(), sz);
+ tagStackStringStorageSize += sz;
+ return QStringRef(&tagStackStringStorage, pos, sz);
+ }
+ inline QStringRef addToStringStorage(const QString &s) {
+ int pos = tagStackStringStorageSize;
+ int sz = s.size();
+ if (pos != tagStackStringStorage.size())
+ tagStackStringStorage.resize(pos);
+ tagStackStringStorage.insert(pos, s.unicode(), sz);
+ tagStackStringStorageSize += sz;
+ return QStringRef(&tagStackStringStorage, pos, sz);
+ }
+
+ QXmlStreamSimpleStack<Tag> tagStack;
+
+
+ inline Tag &tagStack_pop() {
+ Tag& tag = tagStack.pop();
+ tagStackStringStorageSize = tag.tagStackStringStorageSize;
+ namespaceDeclarations.resize(tag.namespaceDeclarationsSize);
+ tagsDone = tagStack.isEmpty();
+ return tag;
+ }
+ inline Tag &tagStack_push() {
+ Tag &tag = tagStack.push();
+ tag.tagStackStringStorageSize = tagStackStringStorageSize;
+ tag.namespaceDeclarationsSize = namespaceDeclarations.size();
+ return tag;
+ }
+};
+
+
+class QXmlStreamEntityResolver;
+#ifndef QT_NO_XMLSTREAMREADER
+class QXmlStreamReaderPrivate : public QXmlStreamReader_Table, public QXmlStreamPrivateTagStack{
+ QXmlStreamReader *q_ptr;
+ Q_DECLARE_PUBLIC(QXmlStreamReader)
+public:
+ QXmlStreamReaderPrivate(QXmlStreamReader *q);
+ ~QXmlStreamReaderPrivate();
+ void init();
+
+ QByteArray rawReadBuffer;
+ QByteArray dataBuffer;
+ uchar firstByte;
+ qint64 nbytesread;
+ QString readBuffer;
+ int readBufferPos;
+ QXmlStreamSimpleStack<uint> putStack;
+ struct Entity {
+ Entity(const QString& str = QString())
+ :value(str), external(false), unparsed(false), literal(false),
+ hasBeenParsed(false), isCurrentlyReferenced(false){}
+ static inline Entity createLiteral(const QString &entity)
+ { Entity result(entity); result.literal = result.hasBeenParsed = true; return result; }
+ QString value;
+ uint external : 1;
+ uint unparsed : 1;
+ uint literal : 1;
+ uint hasBeenParsed : 1;
+ uint isCurrentlyReferenced : 1;
+ };
+ QHash<QString, Entity> entityHash;
+ QHash<QString, Entity> parameterEntityHash;
+ QXmlStreamSimpleStack<Entity *>entityReferenceStack;
+ inline bool referenceEntity(Entity &entity) {
+ if (entity.isCurrentlyReferenced) {
+ raiseWellFormedError(QXmlStream::tr("Recursive entity detected."));
+ return false;
+ }
+ entity.isCurrentlyReferenced = true;
+ entityReferenceStack.push() = &entity;
+ injectToken(ENTITY_DONE);
+ return true;
+ }
+
+
+ QIODevice *device;
+ bool deleteDevice;
+#ifndef QT_NO_TEXTCODEC
+ QTextCodec *codec;
+ QTextDecoder *decoder;
+#endif
+ bool atEnd;
+
+ /*!
+ \sa setType()
+ */
+ QXmlStreamReader::TokenType type;
+ QXmlStreamReader::Error error;
+ QString errorString;
+ QString unresolvedEntity;
+
+ qint64 lineNumber, lastLineStart, characterOffset;
+
+
+ void write(const QString &);
+ void write(const char *);
+
+
+ QXmlStreamAttributes attributes;
+ QStringRef namespaceForPrefix(const QStringRef &prefix);
+ void resolveTag();
+ void resolvePublicNamespaces();
+ void resolveDtd();
+ uint resolveCharRef(int symbolIndex);
+ bool checkStartDocument();
+ void startDocument();
+ void parseError();
+ void checkPublicLiteral(const QStringRef &publicId);
+
+ bool scanDtd;
+ QStringRef lastAttributeValue;
+ bool lastAttributeIsCData;
+ struct DtdAttribute {
+ QStringRef tagName;
+ QStringRef attributeQualifiedName;
+ QStringRef attributePrefix;
+ QStringRef attributeName;
+ QStringRef defaultValue;
+ bool isCDATA;
+ bool isNamespaceAttribute;
+ };
+ QXmlStreamSimpleStack<DtdAttribute> dtdAttributes;
+ struct NotationDeclaration {
+ QStringRef name;
+ QStringRef publicId;
+ QStringRef systemId;
+ };
+ QXmlStreamSimpleStack<NotationDeclaration> notationDeclarations;
+ QXmlStreamNotationDeclarations publicNotationDeclarations;
+ QXmlStreamNamespaceDeclarations publicNamespaceDeclarations;
+
+ struct EntityDeclaration {
+ QStringRef name;
+ QStringRef notationName;
+ QStringRef publicId;
+ QStringRef systemId;
+ QStringRef value;
+ bool parameter;
+ bool external;
+ inline void clear() {
+ name.clear();
+ notationName.clear();
+ publicId.clear();
+ systemId.clear();
+ value.clear();
+ parameter = external = false;
+ }
+ };
+ QXmlStreamSimpleStack<EntityDeclaration> entityDeclarations;
+ QXmlStreamEntityDeclarations publicEntityDeclarations;
+
+ QStringRef text;
+
+ QStringRef prefix, namespaceUri, qualifiedName, name;
+ QStringRef processingInstructionTarget, processingInstructionData;
+ QStringRef dtdName, dtdPublicId, dtdSystemId;
+ QStringRef documentVersion, documentEncoding;
+ uint isEmptyElement : 1;
+ uint isWhitespace : 1;
+ uint isCDATA : 1;
+ uint standalone : 1;
+ uint hasCheckedStartDocument : 1;
+ uint normalizeLiterals : 1;
+ uint hasSeenTag : 1;
+ uint inParseEntity : 1;
+ uint referenceToUnparsedEntityDetected : 1;
+ uint referenceToParameterEntityDetected : 1;
+ uint hasExternalDtdSubset : 1;
+ uint lockEncoding : 1;
+ uint namespaceProcessing : 1;
+
+ int resumeReduction;
+ void resume(int rule);
+
+ inline bool entitiesMustBeDeclared() const {
+ return (!inParseEntity
+ && (standalone
+ || (!referenceToUnparsedEntityDetected
+ && !referenceToParameterEntityDetected // Errata 13 as of 2006-04-25
+ && !hasExternalDtdSubset)));
+ }
+
+ // qlalr parser
+ int tos;
+ int stack_size;
+ struct Value {
+ int pos;
+ int len;
+ int prefix;
+ ushort c;
+ };
+
+ Value *sym_stack;
+ int *state_stack;
+ inline void reallocateStack();
+ inline Value &sym(int index) const
+ { return sym_stack[tos + index - 1]; }
+ QString textBuffer;
+ inline void clearTextBuffer() {
+ if (!scanDtd) {
+ textBuffer.resize(0);
+ textBuffer.reserve(256);
+ }
+ }
+ struct Attribute {
+ Value key;
+ Value value;
+ };
+ QXmlStreamSimpleStack<Attribute> attributeStack;
+
+ inline QStringRef symString(int index) {
+ const Value &symbol = sym(index);
+ return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix);
+ }
+ inline QStringRef symName(int index) {
+ const Value &symbol = sym(index);
+ return QStringRef(&textBuffer, symbol.pos, symbol.len);
+ }
+ inline QStringRef symString(int index, int offset) {
+ const Value &symbol = sym(index);
+ return QStringRef(&textBuffer, symbol.pos + symbol.prefix + offset, symbol.len - symbol.prefix - offset);
+ }
+ inline QStringRef symPrefix(int index) {
+ const Value &symbol = sym(index);
+ if (symbol.prefix)
+ return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1);
+ return QStringRef();
+ }
+ inline QStringRef symString(const Value &symbol) {
+ return QStringRef(&textBuffer, symbol.pos + symbol.prefix, symbol.len - symbol.prefix);
+ }
+ inline QStringRef symName(const Value &symbol) {
+ return QStringRef(&textBuffer, symbol.pos, symbol.len);
+ }
+ inline QStringRef symPrefix(const Value &symbol) {
+ if (symbol.prefix)
+ return QStringRef(&textBuffer, symbol.pos, symbol.prefix - 1);
+ return QStringRef();
+ }
+
+ inline void clearSym() { Value &val = sym(1); val.pos = textBuffer.size(); val.len = 0; }
+
+
+ short token;
+ uint token_char;
+
+ uint filterCarriageReturn();
+ inline uint getChar();
+ inline uint peekChar();
+ inline void putChar(uint c) { putStack.push() = c; }
+ inline void putChar(QChar c) { putStack.push() = c.unicode(); }
+ void putString(const QString &s, int from = 0);
+ void putStringLiteral(const QString &s);
+ void putReplacement(const QString &s);
+ void putReplacementInAttributeValue(const QString &s);
+ uint getChar_helper();
+
+ bool scanUntil(const char *str, short tokenToInject = -1);
+ bool scanString(const char *str, short tokenToInject, bool requireSpace = true);
+ inline void injectToken(ushort tokenToInject) {
+ putChar(int(tokenToInject) << 16);
+ }
+
+ QString resolveUndeclaredEntity(const QString &name);
+ void parseEntity(const QString &value);
+ QXmlStreamReaderPrivate *entityParser;
+
+ bool scanAfterLangleBang();
+ bool scanPublicOrSystem();
+ bool scanNData();
+ bool scanAfterDefaultDecl();
+ bool scanAttType();
+
+
+ // scan optimization functions. Not strictly necessary but LALR is
+ // not very well suited for scanning fast
+ int fastScanLiteralContent();
+ int fastScanSpace();
+ int fastScanContentCharList();
+ int fastScanName(int *prefix = 0);
+ inline int fastScanNMTOKEN();
+
+
+ bool parse();
+ inline void consumeRule(int);
+
+ void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
+ void raiseWellFormedError(const QString &message);
+
+ QXmlStreamEntityResolver *entityResolver;
+
+private:
+ /*! \internal
+ Never assign to variable type directly. Instead use this function.
+
+ This prevents errors from being ignored.
+ */
+ inline void setType(const QXmlStreamReader::TokenType t)
+ {
+ if(type != QXmlStreamReader::Invalid)
+ type = t;
+ }
+};
+
+bool QXmlStreamReaderPrivate::parse()
+{
+ // cleanup currently reported token
+
+ switch (type) {
+ case QXmlStreamReader::StartElement:
+ name.clear();
+ prefix.clear();
+ qualifiedName.clear();
+ namespaceUri.clear();
+ publicNamespaceDeclarations.clear();
+ attributes.clear();
+ if (isEmptyElement) {
+ setType(QXmlStreamReader::EndElement);
+ Tag &tag = tagStack_pop();
+ namespaceUri = tag.namespaceDeclaration.namespaceUri;
+ name = tag.name;
+ qualifiedName = tag.qualifiedName;
+ isEmptyElement = false;
+ return true;
+ }
+ clearTextBuffer();
+ break;
+ case QXmlStreamReader::EndElement:
+ name.clear();
+ prefix.clear();
+ qualifiedName.clear();
+ namespaceUri.clear();
+ clearTextBuffer();
+ break;
+ case QXmlStreamReader::DTD:
+ publicNotationDeclarations.clear();
+ publicEntityDeclarations.clear();
+ dtdName.clear();
+ dtdPublicId.clear();
+ dtdSystemId.clear();
+ Q_FALLTHROUGH();
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::Characters:
+ isCDATA = false;
+ isWhitespace = true;
+ text.clear();
+ clearTextBuffer();
+ break;
+ case QXmlStreamReader::EntityReference:
+ text.clear();
+ name.clear();
+ clearTextBuffer();
+ break;
+ case QXmlStreamReader::ProcessingInstruction:
+ processingInstructionTarget.clear();
+ processingInstructionData.clear();
+ clearTextBuffer();
+ break;
+ case QXmlStreamReader::NoToken:
+ case QXmlStreamReader::Invalid:
+ break;
+ case QXmlStreamReader::StartDocument:
+ lockEncoding = true;
+ documentVersion.clear();
+ documentEncoding.clear();
+#ifndef QT_NO_TEXTCODEC
+ if (decoder && decoder->hasFailure()) {
+ raiseWellFormedError(QXmlStream::tr("Encountered incorrectly encoded content."));
+ readBuffer.clear();
+ return false;
+ }
+#endif
+ Q_FALLTHROUGH();
+ default:
+ clearTextBuffer();
+ ;
+ }
+
+ setType(QXmlStreamReader::NoToken);
+
+
+ // the main parse loop
+ int act, r;
+
+ if (resumeReduction) {
+ act = state_stack[tos-1];
+ r = resumeReduction;
+ resumeReduction = 0;
+ goto ResumeReduction;
+ }
+
+ act = state_stack[tos];
+
+ forever {
+ if (token == -1 && - TERMINAL_COUNT != action_index[act]) {
+ uint cu = getChar();
+ token = NOTOKEN;
+ token_char = cu == ~0U ? cu : ushort(cu);
+ if ((cu != ~0U) && (cu & 0xff0000)) {
+ token = cu >> 16;
+ } else switch (token_char) {
+ case 0xfffe:
+ case 0xffff:
+ token = ERROR;
+ break;
+ case '\r':
+ token = SPACE;
+ if (cu == '\r') {
+ if ((token_char = filterCarriageReturn())) {
+ ++lineNumber;
+ lastLineStart = characterOffset + readBufferPos;
+ break;
+ }
+ } else {
+ break;
+ }
+ Q_FALLTHROUGH();
+ case ~0U: {
+ token = EOF_SYMBOL;
+ if (!tagsDone && !inParseEntity) {
+ int a = t_action(act, token);
+ if (a < 0) {
+ raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
+ return false;
+ }
+ }
+
+ } break;
+ case '\n':
+ ++lineNumber;
+ lastLineStart = characterOffset + readBufferPos;
+ Q_FALLTHROUGH();
+ case ' ':
+ case '\t':
+ token = SPACE;
+ break;
+ case '&':
+ token = AMPERSAND;
+ break;
+ case '#':
+ token = HASH;
+ break;
+ case '\'':
+ token = QUOTE;
+ break;
+ case '\"':
+ token = DBLQUOTE;
+ break;
+ case '<':
+ token = LANGLE;
+ break;
+ case '>':
+ token = RANGLE;
+ break;
+ case '[':
+ token = LBRACK;
+ break;
+ case ']':
+ token = RBRACK;
+ break;
+ case '(':
+ token = LPAREN;
+ break;
+ case ')':
+ token = RPAREN;
+ break;
+ case '|':
+ token = PIPE;
+ break;
+ case '=':
+ token = EQ;
+ break;
+ case '%':
+ token = PERCENT;
+ break;
+ case '/':
+ token = SLASH;
+ break;
+ case ':':
+ token = COLON;
+ break;
+ case ';':
+ token = SEMICOLON;
+ break;
+ case ',':
+ token = COMMA;
+ break;
+ case '-':
+ token = DASH;
+ break;
+ case '+':
+ token = PLUS;
+ break;
+ case '*':
+ token = STAR;
+ break;
+ case '.':
+ token = DOT;
+ break;
+ case '?':
+ token = QUESTIONMARK;
+ break;
+ case '!':
+ token = BANG;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ token = DIGIT;
+ break;
+ default:
+ if (cu < 0x20)
+ token = NOTOKEN;
+ else
+ token = LETTER;
+ break;
+ }
+ }
+
+ act = t_action (act, token);
+ if (act == ACCEPT_STATE) {
+ // reset the parser in case someone resumes (process instructions can follow a valid document)
+ tos = 0;
+ state_stack[tos++] = 0;
+ state_stack[tos] = 0;
+ return true;
+ } else if (act > 0) {
+ if (++tos == stack_size-1)
+ reallocateStack();
+
+ Value &val = sym_stack[tos];
+ val.c = token_char;
+ val.pos = textBuffer.size();
+ val.prefix = 0;
+ val.len = 1;
+ if (token_char)
+ textBuffer += QChar(token_char);
+
+ state_stack[tos] = act;
+ token = -1;
+
+
+ } else if (act < 0) {
+ r = - act - 1;
+
+#if defined (QLALR_DEBUG)
+ int ridx = rule_index[r];
+ printf ("%3d) %s ::=", r + 1, spell[rule_info[ridx]]);
+ ++ridx;
+ for (int i = ridx; i < ridx + rhs[r]; ++i) {
+ int symbol = rule_info[i];
+ if (const char *name = spell[symbol])
+ printf (" %s", name);
+ else
+ printf (" #%d", symbol);
+ }
+ printf ("\n");
+#endif
+
+ tos -= rhs[r];
+ act = state_stack[tos++];
+ ResumeReduction:
+ switch (r) {
+
+ case 0:
+ setType(QXmlStreamReader::EndDocument);
+ break;
+
+ case 1:
+ if (type != QXmlStreamReader::Invalid) {
+ if (hasSeenTag || inParseEntity) {
+ setType(QXmlStreamReader::EndDocument);
+ } else {
+ raiseError(QXmlStreamReader::NotWellFormedError, QXmlStream::tr("Start tag expected."));
+ // reset the parser
+ tos = 0;
+ state_stack[tos++] = 0;
+ state_stack[tos] = 0;
+ return false;
+ }
+ }
+ break;
+
+ case 10:
+ entityReferenceStack.pop()->isCurrentlyReferenced = false;
+ clearSym();
+ break;
+
+ case 11:
+ if (!scanString(spell[VERSION], VERSION, false) && atEnd) {
+ resume(11);
+ return false;
+ }
+ break;
+
+ case 12:
+ setType(QXmlStreamReader::StartDocument);
+ documentVersion = symString(6);
+ startDocument();
+ break;
+
+ case 13:
+ hasExternalDtdSubset = true;
+ dtdSystemId = symString(2);
+ break;
+
+ case 14:
+ checkPublicLiteral(symString(2));
+ dtdPublicId = symString(2);
+ dtdSystemId = symString(4);
+ hasExternalDtdSubset = true;
+ break;
+
+ case 16:
+ if (!scanPublicOrSystem() && atEnd) {
+ resume(16);
+ return false;
+ }
+ dtdName = symString(3);
+ break;
+
+ case 17:
+ case 18:
+ dtdName = symString(3);
+ Q_FALLTHROUGH();
+
+ case 19:
+ case 20:
+ setType(QXmlStreamReader::DTD);
+ text = &textBuffer;
+ break;
+
+ case 21:
+ scanDtd = true;
+ break;
+
+ case 22:
+ scanDtd = false;
+ break;
+
+ case 37:
+ if (!scanString(spell[EMPTY], EMPTY, false)
+ && !scanString(spell[ANY], ANY, false)
+ && atEnd) {
+ resume(37);
+ return false;
+ }
+ break;
+
+ case 43:
+ if (!scanString(spell[PCDATA], PCDATA, false) && atEnd) {
+ resume(43);
+ return false;
+ }
+ break;
+
+ case 68: {
+ lastAttributeIsCData = true;
+ } break;
+
+ case 78:
+ if (!scanAfterDefaultDecl() && atEnd) {
+ resume(78);
+ return false;
+ }
+ break;
+
+ case 83:
+ sym(1) = sym(2);
+ lastAttributeValue.clear();
+ lastAttributeIsCData = false;
+ if (!scanAttType() && atEnd) {
+ resume(83);
+ return false;
+ }
+ break;
+
+ case 84: {
+ DtdAttribute &dtdAttribute = dtdAttributes.push();
+ dtdAttribute.tagName.clear();
+ dtdAttribute.isCDATA = lastAttributeIsCData;
+ dtdAttribute.attributePrefix = addToStringStorage(symPrefix(1));
+ dtdAttribute.attributeName = addToStringStorage(symString(1));
+ dtdAttribute.attributeQualifiedName = addToStringStorage(symName(1));
+ dtdAttribute.isNamespaceAttribute = (dtdAttribute.attributePrefix == QLatin1String("xmlns")
+ || (dtdAttribute.attributePrefix.isEmpty()
+ && dtdAttribute.attributeName == QLatin1String("xmlns")));
+ if (lastAttributeValue.isNull()) {
+ dtdAttribute.defaultValue.clear();
+ } else {
+ if (dtdAttribute.isCDATA)
+ dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue);
+ else
+ dtdAttribute.defaultValue = addToStringStorage(lastAttributeValue.toString().simplified());
+
+ }
+ } break;
+
+ case 88: {
+ if (referenceToUnparsedEntityDetected && !standalone)
+ break;
+ int n = dtdAttributes.size();
+ QStringRef tagName = addToStringStorage(symName(3));
+ while (n--) {
+ DtdAttribute &dtdAttribute = dtdAttributes[n];
+ if (!dtdAttribute.tagName.isNull())
+ break;
+ dtdAttribute.tagName = tagName;
+ for (int i = 0; i < n; ++i) {
+ if ((dtdAttributes[i].tagName.isNull() || dtdAttributes[i].tagName == tagName)
+ && dtdAttributes[i].attributeQualifiedName == dtdAttribute.attributeQualifiedName) {
+ dtdAttribute.attributeQualifiedName.clear(); // redefined, delete it
+ break;
+ }
+ }
+ }
+ } break;
+
+ case 89: {
+ if (!scanPublicOrSystem() && atEnd) {
+ resume(89);
+ return false;
+ }
+ EntityDeclaration &entityDeclaration = entityDeclarations.push();
+ entityDeclaration.clear();
+ entityDeclaration.name = symString(3);
+ } break;
+
+ case 90: {
+ if (!scanPublicOrSystem() && atEnd) {
+ resume(90);
+ return false;
+ }
+ EntityDeclaration &entityDeclaration = entityDeclarations.push();
+ entityDeclaration.clear();
+ entityDeclaration.name = symString(5);
+ entityDeclaration.parameter = true;
+ } break;
+
+ case 91: {
+ if (!scanNData() && atEnd) {
+ resume(91);
+ return false;
+ }
+ EntityDeclaration &entityDeclaration = entityDeclarations.top();
+ entityDeclaration.systemId = symString(3);
+ entityDeclaration.external = true;
+ } break;
+
+ case 92: {
+ if (!scanNData() && atEnd) {
+ resume(92);
+ return false;
+ }
+ EntityDeclaration &entityDeclaration = entityDeclarations.top();
+ checkPublicLiteral((entityDeclaration.publicId = symString(3)));
+ entityDeclaration.systemId = symString(5);
+ entityDeclaration.external = true;
+ } break;
+
+ case 93: {
+ EntityDeclaration &entityDeclaration = entityDeclarations.top();
+ entityDeclaration.notationName = symString(3);
+ if (entityDeclaration.parameter)
+ raiseWellFormedError(QXmlStream::tr("NDATA in parameter entity declaration."));
+ }
+ Q_FALLTHROUGH();
+
+ case 94:
+ case 95: {
+ if (referenceToUnparsedEntityDetected && !standalone) {
+ entityDeclarations.pop();
+ break;
+ }
+ EntityDeclaration &entityDeclaration = entityDeclarations.top();
+ if (!entityDeclaration.external)
+ entityDeclaration.value = symString(2);
+ QString entityName = entityDeclaration.name.toString();
+ QHash<QString, Entity> &hash = entityDeclaration.parameter ? parameterEntityHash : entityHash;
+ if (!hash.contains(entityName)) {
+ Entity entity(entityDeclaration.value.toString());
+ entity.unparsed = (!entityDeclaration.notationName.isNull());
+ entity.external = entityDeclaration.external;
+ hash.insert(entityName, entity);
+ }
+ } break;
+
+ case 96: {
+ setType(QXmlStreamReader::ProcessingInstruction);
+ int pos = sym(4).pos + sym(4).len;
+ processingInstructionTarget = symString(3);
+ if (scanUntil("?>")) {
+ processingInstructionData = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 2);
+ const QString piTarget(processingInstructionTarget.toString());
+ if (!piTarget.compare(QLatin1String("xml"), Qt::CaseInsensitive)) {
+ raiseWellFormedError(QXmlStream::tr("XML declaration not at start of document."));
+ }
+ else if(!QXmlUtils::isNCName(piTarget))
+ raiseWellFormedError(QXmlStream::tr("%1 is an invalid processing instruction name.").arg(piTarget));
+ } else if (type != QXmlStreamReader::Invalid){
+ resume(96);
+ return false;
+ }
+ } break;
+
+ case 97:
+ setType(QXmlStreamReader::ProcessingInstruction);
+ processingInstructionTarget = symString(3);
+ if (!processingInstructionTarget.toString().compare(QLatin1String("xml"), Qt::CaseInsensitive))
+ raiseWellFormedError(QXmlStream::tr("Invalid processing instruction name."));
+ break;
+
+ case 98:
+ if (!scanAfterLangleBang() && atEnd) {
+ resume(98);
+ return false;
+ }
+ break;
+
+ case 99:
+ if (!scanUntil("--")) {
+ resume(99);
+ return false;
+ }
+ break;
+
+ case 100: {
+ setType(QXmlStreamReader::Comment);
+ int pos = sym(1).pos + 4;
+ text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3);
+ } break;
+
+ case 101: {
+ setType(QXmlStreamReader::Characters);
+ isCDATA = true;
+ isWhitespace = false;
+ int pos = sym(2).pos;
+ if (scanUntil("]]>", -1)) {
+ text = QStringRef(&textBuffer, pos, textBuffer.size() - pos - 3);
+ } else {
+ resume(101);
+ return false;
+ }
+ } break;
+
+ case 102: {
+ if (!scanPublicOrSystem() && atEnd) {
+ resume(102);
+ return false;
+ }
+ NotationDeclaration &notationDeclaration = notationDeclarations.push();
+ notationDeclaration.name = symString(3);
+ } break;
+
+ case 103: {
+ NotationDeclaration &notationDeclaration = notationDeclarations.top();
+ notationDeclaration.systemId = symString(3);
+ notationDeclaration.publicId.clear();
+ } break;
+
+ case 104: {
+ NotationDeclaration &notationDeclaration = notationDeclarations.top();
+ notationDeclaration.systemId.clear();
+ checkPublicLiteral((notationDeclaration.publicId = symString(3)));
+ } break;
+
+ case 105: {
+ NotationDeclaration &notationDeclaration = notationDeclarations.top();
+ checkPublicLiteral((notationDeclaration.publicId = symString(3)));
+ notationDeclaration.systemId = symString(5);
+ } break;
+
+ case 129:
+ isWhitespace = false;
+ Q_FALLTHROUGH();
+
+ case 130:
+ sym(1).len += fastScanContentCharList();
+ if (atEnd && !inParseEntity) {
+ resume(130);
+ return false;
+ }
+ break;
+
+ case 139:
+ if (!textBuffer.isEmpty()) {
+ setType(QXmlStreamReader::Characters);
+ text = &textBuffer;
+ }
+ break;
+
+ case 140:
+ case 141:
+ clearSym();
+ break;
+
+ case 142:
+ case 143:
+ sym(1) = sym(2);
+ break;
+
+ case 144:
+ case 145:
+ case 146:
+ case 147:
+ sym(1).len += sym(2).len;
+ break;
+
+ case 173:
+ if (normalizeLiterals)
+ textBuffer.data()[textBuffer.size()-1] = QLatin1Char(' ');
+ break;
+
+ case 174:
+ sym(1).len += fastScanLiteralContent();
+ if (atEnd) {
+ resume(174);
+ return false;
+ }
+ break;
+
+ case 175: {
+ if (!QXmlUtils::isPublicID(symString(1).toString())) {
+ raiseWellFormedError(QXmlStream::tr("%1 is an invalid PUBLIC identifier.").arg(symString(1).toString()));
+ resume(175);
+ return false;
+ }
+ } break;
+
+ case 176:
+ case 177:
+ clearSym();
+ break;
+
+ case 178:
+ case 179:
+ sym(1) = sym(2);
+ break;
+
+ case 180:
+ case 181:
+ case 182:
+ case 183:
+ sym(1).len += sym(2).len;
+ break;
+
+ case 213:
+ case 214:
+ clearSym();
+ break;
+
+ case 215:
+ case 216:
+ sym(1) = sym(2);
+ lastAttributeValue = symString(1);
+ break;
+
+ case 217:
+ case 218:
+ case 219:
+ case 220:
+ sym(1).len += sym(2).len;
+ break;
+
+ case 229: {
+ QStringRef prefix = symPrefix(1);
+ if (prefix.isEmpty() && symString(1) == QLatin1String("xmlns") && namespaceProcessing) {
+ NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
+ namespaceDeclaration.prefix.clear();
+
+ const QStringRef ns(symString(5));
+ if(ns == QLatin1String("http://www.w3.org/2000/xmlns/") ||
+ ns == QLatin1String("http://www.w3.org/XML/1998/namespace"))
+ raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration."));
+ else
+ namespaceDeclaration.namespaceUri = addToStringStorage(ns);
+ } else {
+ Attribute &attribute = attributeStack.push();
+ attribute.key = sym(1);
+ attribute.value = sym(5);
+
+ QStringRef attributeQualifiedName = symName(1);
+ bool normalize = false;
+ for (int a = 0; a < dtdAttributes.size(); ++a) {
+ DtdAttribute &dtdAttribute = dtdAttributes[a];
+ if (!dtdAttribute.isCDATA
+ && dtdAttribute.tagName == qualifiedName
+ && dtdAttribute.attributeQualifiedName == attributeQualifiedName
+ ) {
+ normalize = true;
+ break;
+ }
+ }
+ if (normalize) {
+ // normalize attribute value (simplify and trim)
+ int pos = textBuffer.size();
+ int n = 0;
+ bool wasSpace = true;
+ for (int i = 0; i < attribute.value.len; ++i) {
+ QChar c = textBuffer.at(attribute.value.pos + i);
+ if (c.unicode() == ' ') {
+ if (wasSpace)
+ continue;
+ wasSpace = true;
+ } else {
+ wasSpace = false;
+ }
+ textBuffer += textBuffer.at(attribute.value.pos + i);
+ ++n;
+ }
+ if (wasSpace)
+ while (n && textBuffer.at(pos + n - 1).unicode() == ' ')
+ --n;
+ attribute.value.pos = pos;
+ attribute.value.len = n;
+ }
+ if (prefix == QLatin1String("xmlns") && namespaceProcessing) {
+ NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
+ QStringRef namespacePrefix = symString(attribute.key);
+ QStringRef namespaceUri = symString(attribute.value);
+ attributeStack.pop();
+ if (((namespacePrefix == QLatin1String("xml"))
+ ^ (namespaceUri == QLatin1String("http://www.w3.org/XML/1998/namespace")))
+ || namespaceUri == QLatin1String("http://www.w3.org/2000/xmlns/")
+ || namespaceUri.isEmpty()
+ || namespacePrefix == QLatin1String("xmlns"))
+ raiseWellFormedError(QXmlStream::tr("Illegal namespace declaration."));
+
+ namespaceDeclaration.prefix = addToStringStorage(namespacePrefix);
+ namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
+ }
+ }
+ } break;
+
+ case 235: {
+ normalizeLiterals = true;
+ Tag &tag = tagStack_push();
+ prefix = tag.namespaceDeclaration.prefix = addToStringStorage(symPrefix(2));
+ name = tag.name = addToStringStorage(symString(2));
+ qualifiedName = tag.qualifiedName = addToStringStorage(symName(2));
+ if ((!prefix.isEmpty() && !QXmlUtils::isNCName(prefix)) || !QXmlUtils::isNCName(name))
+ raiseWellFormedError(QXmlStream::tr("Invalid XML name."));
+ } break;
+
+ case 236:
+ isEmptyElement = true;
+ Q_FALLTHROUGH();
+
+ case 237:
+ setType(QXmlStreamReader::StartElement);
+ resolveTag();
+ if (tagStack.size() == 1 && hasSeenTag && !inParseEntity)
+ raiseWellFormedError(QXmlStream::tr("Extra content at end of document."));
+ hasSeenTag = true;
+ break;
+
+ case 238: {
+ setType(QXmlStreamReader::EndElement);
+ Tag &tag = tagStack_pop();
+
+ namespaceUri = tag.namespaceDeclaration.namespaceUri;
+ name = tag.name;
+ qualifiedName = tag.qualifiedName;
+ if (qualifiedName != symName(3))
+ raiseWellFormedError(QXmlStream::tr("Opening and ending tag mismatch."));
+ } break;
+
+ case 239:
+ if (entitiesMustBeDeclared()) {
+ raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(unresolvedEntity));
+ break;
+ }
+ setType(QXmlStreamReader::EntityReference);
+ name = &unresolvedEntity;
+ break;
+
+ case 240: {
+ sym(1).len += sym(2).len + 1;
+ QString reference = symString(2).toString();
+ if (entityHash.contains(reference)) {
+ Entity &entity = entityHash[reference];
+ if (entity.unparsed) {
+ raiseWellFormedError(QXmlStream::tr("Reference to unparsed entity '%1'.").arg(reference));
+ } else {
+ if (!entity.hasBeenParsed) {
+ parseEntity(entity.value);
+ entity.hasBeenParsed = true;
+ }
+ if (entity.literal)
+ putStringLiteral(entity.value);
+ else if (referenceEntity(entity))
+ putReplacement(entity.value);
+ textBuffer.chop(2 + sym(2).len);
+ clearSym();
+ }
+ break;
+ }
+
+ if (entityResolver) {
+ QString replacementText = resolveUndeclaredEntity(reference);
+ if (!replacementText.isNull()) {
+ putReplacement(replacementText);
+ textBuffer.chop(2 + sym(2).len);
+ clearSym();
+ break;
+ }
+ }
+
+ injectToken(UNRESOLVED_ENTITY);
+ unresolvedEntity = symString(2).toString();
+ textBuffer.chop(2 + sym(2).len);
+ clearSym();
+
+ } break;
+
+ case 241: {
+ sym(1).len += sym(2).len + 1;
+ QString reference = symString(2).toString();
+ if (parameterEntityHash.contains(reference)) {
+ referenceToParameterEntityDetected = true;
+ Entity &entity = parameterEntityHash[reference];
+ if (entity.unparsed || entity.external) {
+ referenceToUnparsedEntityDetected = true;
+ } else {
+ if (referenceEntity(entity))
+ putString(entity.value);
+ textBuffer.chop(2 + sym(2).len);
+ clearSym();
+ }
+ } else if (entitiesMustBeDeclared()) {
+ raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(symString(2).toString()));
+ }
+ } break;
+
+ case 242:
+ sym(1).len += sym(2).len + 1;
+ break;
+
+ case 243: {
+ sym(1).len += sym(2).len + 1;
+ QString reference = symString(2).toString();
+ if (entityHash.contains(reference)) {
+ Entity &entity = entityHash[reference];
+ if (entity.unparsed || entity.value.isNull()) {
+ raiseWellFormedError(QXmlStream::tr("Reference to external entity '%1' in attribute value.").arg(reference));
+ break;
+ }
+ if (!entity.hasBeenParsed) {
+ parseEntity(entity.value);
+ entity.hasBeenParsed = true;
+ }
+ if (entity.literal)
+ putStringLiteral(entity.value);
+ else if (referenceEntity(entity))
+ putReplacementInAttributeValue(entity.value);
+ textBuffer.chop(2 + sym(2).len);
+ clearSym();
+ break;
+ }
+
+ if (entityResolver) {
+ QString replacementText = resolveUndeclaredEntity(reference);
+ if (!replacementText.isNull()) {
+ putReplacement(replacementText);
+ textBuffer.chop(2 + sym(2).len);
+ clearSym();
+ break;
+ }
+ }
+ if (entitiesMustBeDeclared()) {
+ raiseWellFormedError(QXmlStream::tr("Entity '%1' not declared.").arg(reference));
+ }
+ } break;
+
+ case 244: {
+ if (uint s = resolveCharRef(3)) {
+ if (s >= 0xffff)
+ putStringLiteral(QString::fromUcs4(&s, 1));
+ else
+ putChar((LETTER << 16) | s);
+
+ textBuffer.chop(3 + sym(3).len);
+ clearSym();
+ } else {
+ raiseWellFormedError(QXmlStream::tr("Invalid character reference."));
+ }
+ } break;
+
+ case 247:
+ case 248:
+ sym(1).len += sym(2).len;
+ break;
+
+ case 259:
+ sym(1).len += fastScanSpace();
+ if (atEnd) {
+ resume(259);
+ return false;
+ }
+ break;
+
+ case 262: {
+ sym(1).len += fastScanName(&sym(1).prefix);
+ if (atEnd) {
+ resume(262);
+ return false;
+ }
+ } break;
+
+ case 263:
+ sym(1).len += fastScanName();
+ if (atEnd) {
+ resume(263);
+ return false;
+ }
+ break;
+
+ case 264:
+ case 265:
+ case 266:
+ case 267:
+ case 268:
+ sym(1).len += fastScanNMTOKEN();
+ if (atEnd) {
+ resume(268);
+ return false;
+ }
+
+ break;
+
+ default:
+ ;
+ } // switch
+ act = state_stack[tos] = nt_action (act, lhs[r] - TERMINAL_COUNT);
+ if (type != QXmlStreamReader::NoToken)
+ return true;
+ } else {
+ parseError();
+ break;
+ }
+ }
+ return false;
+}
+#endif //QT_NO_XMLSTREAMREADER.xml
+
+
+#endif // QXMLSTREAM_P_H
+
diff --git a/src/dbus/doc/src/qtdbus-index.qdoc b/src/dbus/doc/src/qtdbus-index.qdoc
index 080066cfa8..eed5e42731 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/gui/configure.json b/src/gui/configure.json
index ccaf38e4b7..27e913877f 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -167,25 +167,20 @@
"label": "Fontconfig",
"test": {
"head": [
- "#include <ft2build.h>",
- "#include FT_FREETYPE_H",
"#include <fontconfig/fontconfig.h>",
"#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",
@@ -637,7 +632,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",
diff --git a/src/gui/doc/src/qtgui.qdoc b/src/gui/doc/src/qtgui.qdoc
index da3d419735..010659df8c 100644
--- a/src/gui/doc/src/qtgui.qdoc
+++ b/src/gui/doc/src/qtgui.qdoc
@@ -215,12 +215,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/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 36c9b1a964..f7da94d111 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -2122,7 +2122,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
) {
@@ -2158,7 +2158,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/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 27ea3864b9..6f332c8ad6 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
diff --git a/src/gui/kernel/qplatforminputcontext.cpp b/src/gui/kernel/qplatforminputcontext.cpp
index 3f59116e9a..9771e6ba11 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<QInputMethodEvent::Attribute> imAttributes;
imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant()));
QInputMethodEvent event(QString(), imAttributes);
diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp
index 1b56c7d9f2..c98b879a15 100644
--- a/src/gui/kernel/qsimpledrag.cpp
+++ b/src/gui/kernel/qsimpledrag.cpp
@@ -58,6 +58,7 @@
#include <QtCore/QEventLoop>
#include <QtCore/QDebug>
+#include <QtCore/QLoggingCategory>
#include <private/qguiapplication_p.h>
#include <private/qdnd_p.h>
@@ -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,9 +97,9 @@ 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_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<QMouseEvent *>(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<QMouseEvent *>(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()
{
}
@@ -366,6 +387,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 4db8eb4505..e56c7bf306 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();
@@ -131,9 +134,6 @@ protected:
virtual void cancel() override;
virtual void move(const QPoint &globalPos) override;
virtual void drop(const QPoint &globalPos) override;
-
-private:
- QWindow *m_current_window;
};
#endif // QT_NO_DRAGANDDROP
diff --git a/src/gui/painting/qmatrix.h b/src/gui/painting/qmatrix.h
index 74ecef767e..d8a4fcfb1c 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<void *>(this), static_cast<void *>(&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<void *>(this), static_cast<void *>(&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 79835b36e2..63c4a241c1 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<void *>(this), static_cast<void *>(&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<void *>(this), static_cast<void *>(&other), sizeof(QTransform)); }
QTransform(const QTransform &other) Q_DECL_NOTHROW // = default
: affine(Qt::Uninitialized)
- { memcpy(this, &other, sizeof(QTransform)); }
+ { memcpy(static_cast<void *>(this), static_cast<const void *>(&other), sizeof(QTransform)); }
#endif
bool isAffine() const;
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 89f1328241..90c1a12acd 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<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) {
- memset(offsets, 0, (numGlyphs * SpaceNeeded));
+ memset(static_cast<void *>(offsets), 0, (numGlyphs * SpaceNeeded));
} else {
const int num = last - first;
- memset(offsets + first, 0, num * sizeof(QFixedPoint));
+ memset(static_cast<void *>(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<void *>(advances + first), 0, num * sizeof(QFixed));
+ memset(static_cast<void *>(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 7e4efa28f8..067f8473ea 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<void *>(this), static_cast<void *>(&other), sizeof(iterator)); }
iterator &operator=(iterator &&other) Q_DECL_NOTHROW // = default
- { memcpy(this, &other, sizeof(iterator)); return *this; }
+ { memcpy(static_cast<void *>(this), static_cast<void *>(&other), sizeof(iterator)); return *this; }
#endif
QTextFrame *parentFrame() const { return f; }
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 2d771b5637..1fc7817fe8 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -541,12 +541,14 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
directories << ministroPath;
nameFilters << QLatin1String("*.der");
platformEncodingFormat = QSsl::Der;
+# ifndef Q_OS_ANDROID_EMBEDDED
if (ministroPath.isEmpty()) {
QList<QByteArray> 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 ced861805b..6f34c6c888 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -210,7 +210,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<QByteArray> fetchSslCertificateData();
#endif
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
index 949ebc3d2a..2783effaf1 100644
--- a/src/network/ssl/ssl.pri
+++ b/src/network/ssl/ssl.pri
@@ -82,7 +82,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/opengl/doc/src/qtopengl-index.qdoc b/src/opengl/doc/src/qtopengl-index.qdoc
index 6ab888a14d..30b657f6db 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/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
index 674ab29012..7a9a98573e 100644
--- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
+++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
@@ -45,7 +45,7 @@
#include <QtPlatformHeaders/QEGLNativeContext>
#include <QDebug>
-#ifdef Q_OS_ANDROID
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
#include <QtCore/private/qjnihelpers_p.h>
#endif
#ifndef Q_OS_WIN
@@ -332,7 +332,7 @@ void QEGLPlatformContext::updateFormatFromGL()
QByteArray version = QByteArray(reinterpret_cast<const char *>(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/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
index beec8e763c..cc0246b64a 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
@@ -993,9 +993,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 f5585da7de..d498b0ac8b 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;
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
index 2edee51989..5eb5cd8a30 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
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
index 675f689ace..25ff69d877 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
@@ -182,6 +182,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 1f7b346909..b77aaa27c1 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/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro
index 824fd0388f..afdc613167 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/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index fe4c5be4cb..f548a1fa96 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()
@@ -595,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);
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 32be9ad4ee..a94e0dc517 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -311,6 +311,24 @@ QT_USE_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
{
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 00bfc8bef5..94f2125bad 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -415,6 +415,13 @@ static QString strippedText(QString s)
} else {
QList<QUrl> 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;
}
@@ -442,10 +449,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
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 7a550b163b..b3c2d5ae90 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -44,9 +44,11 @@
#include <QtCore/QtDebug>
#include "qcocoaapplication.h"
+#include "qcocoaintegration.h"
#include "qcocoamenuloader.h"
#include "qcocoamenubar.h"
#include "qcocoawindow.h"
+#include "qcocoascreen.h"
QT_BEGIN_NAMESPACE
@@ -364,8 +366,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<QCocoaScreen *>(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
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index e756f0aeb0..f4c968ab57 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/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
index f3efbea60b..29cfd4ea79 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 6f79cd96d3..f835dbf6d4 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
@@ -59,13 +59,13 @@
#include <QtInputSupport/private/qlibinputhandler_p.h>
#endif
-#if QT_CONFIG(evdev) && !defined(Q_OS_ANDROID)
+#if QT_CONFIG(evdev)
#include <QtInputSupport/private/qevdevmousemanager_p.h>
#include <QtInputSupport/private/qevdevkeyboardmanager_p.h>
#include <QtInputSupport/private/qevdevtouchmanager_p.h>
#endif
-#if QT_CONFIG(tslib) && !defined(Q_OS_ANDROID)
+#if QT_CONFIG(tslib)
#include <QtInputSupport/private/qtslib_p.h>
#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 9ccc2b54b9..e61887618f 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
@@ -36,7 +36,7 @@ qtConfig(directfb) {
qtConfig(linuxfb): SUBDIRS += linuxfb
-qtConfig(vnc): SUBDIRS += vnc
+qtHaveModule(network):qtConfig(vnc): SUBDIRS += vnc
freebsd {
SUBDIRS += bsdfb
diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro
index 15d33200e5..96bfa1dd19 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 33ce0f924c..48766fc435 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 183be11ddc..3a3840f13c 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 d35a4f0bba..d4493943e2 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<QQnxScreen*>(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<QQnxGLContext*>(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);
}
-bool QQnxGLContext::makeCurrent(QPlatformSurface *surface)
+EGLSurface QQnxGLContext::eglSurfaceForPlatformSurface(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<QQnxEglWindow*>(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);
+ QQnxEglWindow *window = static_cast<QQnxEglWindow *>(surface);
+ window->ensureInitialized(this);
+ return window->surface();
}
-void QQnxGLContext::doneCurrent()
+bool QQnxGLContext::makeCurrent(QPlatformSurface *surface)
{
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<QQnxEglWindow*>(surface);
- if (!platformWindow)
- return;
-
- platformWindow->swapEGLBuffers();
-}
-QFunctionPointer QQnxGLContext::getProcAddress(const char *procName)
-{
- qGLContextDebug();
+ QEGLPlatformContext::swapBuffers(surface);
- // 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<QFunctionPointer>(eglGetProcAddress(procName));
- if (!result)
- result = reinterpret_cast<QFunctionPointer>(dlsym(RTLD_DEFAULT, procName));
- return result;
-}
-
-bool QQnxGLContext::isSharing() const
-{
- return m_eglShareContext != EGL_NO_CONTEXT;
-}
-
-EGLDisplay QQnxGLContext::getEglDisplay() {
- return ms_eglDisplay;
+ QQnxEglWindow *platformWindow = static_cast<QQnxEglWindow*>(surface);
+ platformWindow->windowPosted();
}
-EGLint *QQnxGLContext::contextAttrs(const QSurfaceFormat &format)
+void QQnxGLContext::doneCurrent()
{
- 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 6e5408e8bf..19179a80e2 100644
--- a/src/plugins/platforms/qnx/qqnxglcontext.h
+++ b/src/plugins/platforms/qnx/qqnxglcontext.h
@@ -46,49 +46,31 @@
#include <QtCore/QSize>
#include <EGL/egl.h>
+#include <QtEglSupport/private/qeglplatformcontext_p.h>
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;
-
- virtual QSurfaceFormat format() const override { return m_windowFormat; }
- bool isSharing() const override;
+ void doneCurrent() 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 072510e052..bffe7ee34b 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<QQnxScreen*>(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 468fe9cd91..3eebb9c742 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<QQnxGLContext*>(context->handle())->getEglContext();
+ return static_cast<QQnxGLContext*>(context->handle())->eglContext();
return 0;
}
diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h
index 8a498434aa..a6d5623d04 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.h
+++ b/src/plugins/platforms/qnx/qqnxscreen.h
@@ -49,10 +49,14 @@
#include <screen/screen.h>
-// 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 <sys/neutrino.h>
-#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 dfcca78f80..2895a547b1 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;
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 70ee708b61..80ee7b2287 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -68,7 +68,6 @@
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>
#include <QtCore/QUuid>
-#include <QtCore/QRegularExpression>
#include <QtCore/QTemporaryFile>
#include <QtCore/private/qsystemlibrary_p.h>
@@ -1135,12 +1134,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
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index ada124b5af..038ee5cd62 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -2558,7 +2558,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);
}
}
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 56a737e882..21024385b0 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)) {
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 5b05a230e4..61cfed4db7 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -2071,7 +2071,7 @@ bool QXcbWindow::isEmbedded() const
QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
{
if (!m_embedded)
- return pos;
+ return QPlatformWindow::mapToGlobal(pos);
QPoint ret;
auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(),
@@ -2088,7 +2088,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;
auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(),
diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
index 0b67739095..ec4ff68e8d 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
@@ -41,6 +41,7 @@
#include <QtGui/qwindow.h>
#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/qpa/qplatformwindow.h>
#undef signals
#include <gtk/gtk.h>
@@ -426,9 +427,11 @@ 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();
- if (parentWindow)
- m_targetPos = parentWindow->mapToGlobal(m_targetPos);
+ m_targetPos = QPoint(targetRect.x(), targetRect.y() + targetRect.height());
+
+ 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());
}
diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
index 6447776f25..077955eb4e 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 8f03b84bb6..54296d2ff1 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3theme.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.h
@@ -59,6 +59,8 @@ public:
QPlatformMenuItem* createPlatformMenuItem() const override;
static const char *name;
+private:
+ static bool useNativeFileDialog();
};
QT_END_NAMESPACE
diff --git a/src/printsupport/doc/src/qtprintsupport-index.qdoc b/src/printsupport/doc/src/qtprintsupport-index.qdoc
index 7ac448f66f..a8a0f0cb20 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/sql/doc/src/qtsql.qdoc b/src/sql/doc/src/qtsql.qdoc
index 56d714becf..f0d74739b0 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/src.pro b/src/src.pro
index 3b93b1a9d8..1f7c5d99c1 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -210,9 +210,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
@@ -224,7 +226,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/src/testlib/doc/src/qttest-index.qdoc b/src/testlib/doc/src/qttest-index.qdoc
index 7b3e96f72e..b3c2be7375 100644
--- a/src/testlib/doc/src/qttest-index.qdoc
+++ b/src/testlib/doc/src/qttest-index.qdoc
@@ -55,12 +55,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}
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index 4cda5f34ad..3d91bdef34 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
diff --git a/src/widgets/doc/src/qtwidgets-index.qdoc b/src/widgets/doc/src/qtwidgets-index.qdoc
index 7cd1c8d735..1a23d172dd 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/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
index 585cfddff5..c90a61d4ff 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)),
@@ -2160,14 +2160,28 @@ void QHeaderViewPrivate::_q_sectionsAboutToBeChanged()
|| 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_sectionsChanged()
@@ -2175,25 +2189,57 @@ void QHeaderViewPrivate::_q_sectionsChanged()
Q_Q(QHeaderView);
viewport->update();
- const auto hiddenSections = persistentHiddenSections;
- persistentHiddenSections.clear();
-
- clear();
- q->initializeSections();
- invalidateCachedSizeHint();
+ const auto oldPersistentSections = layoutChangePersistentSections;
+ layoutChangePersistentSections.clear();
- 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 d844274618..24dc3bf075 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());
@@ -300,7 +296,6 @@ public:
QLabel *sectionIndicator;
#endif
QHeaderView::ResizeMode globalResizeMode;
- QList<QPersistentModelIndex> persistentHiddenSections;
mutable bool sectionStartposRecalc;
int resizeContentsPrecision;
// header sections
@@ -331,6 +326,11 @@ public:
};
QVector<SectionItem> sectionItems;
+ struct LayoutChangeItem {
+ QPersistentModelIndex index;
+ SectionItem section;
+ };
+ QVector<LayoutChangeItem> layoutChangePersistentSections;
void createSectionItems(int start, int end, int size, QHeaderView::ResizeMode mode);
void removeSectionsFromSectionItems(int start, int end);
@@ -384,6 +384,7 @@ public:
};
Q_DECLARE_TYPEINFO(QHeaderViewPrivate::SectionItem, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QHeaderViewPrivate::LayoutChangeItem, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp
index 9b7797993c..ebeefad682 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();
}
/*!
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index bc5062e942..74f2dc0c41 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1482,7 +1482,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();
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index 26f651906a..554c45d570 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -775,16 +775,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;
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
new file mode 100644
index 0000000000..e6436f82a6
--- /dev/null
+++ b/src/widgets/styles/qmacstyle_mac.mm
@@ -0,0 +1,7160 @@
+/****************************************************************************
+**
+** 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 <AppKit/AppKit.h>
+
+#include "qmacstyle_mac_p.h"
+#include "qmacstyle_mac_p_p.h"
+
+#define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
+//#define DEBUG_SIZE_CONSTRAINT
+
+#include <private/qcore_mac_p.h>
+#if QT_CONFIG(tabbar)
+#include <private/qtabbar_p.h>
+#endif
+#include <private/qpainter_p.h>
+#include <qapplication.h>
+#include <qbitmap.h>
+#if QT_CONFIG(combobox)
+#include <private/qcombobox_p.h>
+#include <qcombobox.h>
+#endif
+#if QT_CONFIG(dialogbuttonbox)
+#include <qdialogbuttonbox.h>
+#endif
+#if QT_CONFIG(dockwidget)
+#include <qdockwidget.h>
+#endif
+#include <qevent.h>
+#include <qfocusframe.h>
+#include <qformlayout.h>
+#include <qgroupbox.h>
+#include <qhash.h>
+#include <qheaderview.h>
+#if QT_CONFIG(lineedit)
+#include <qlineedit.h>
+#endif
+#if QT_CONFIG(mainwindow)
+#include <qmainwindow.h>
+#endif
+#if QT_CONFIG(mdiarea)
+#include <qmdisubwindow.h>
+#endif
+#if QT_CONFIG(menubar)
+#include <qmenubar.h>
+#endif
+#include <qpaintdevice.h>
+#include <qpainter.h>
+#include <qpixmapcache.h>
+#include <qpointer.h>
+#if QT_CONFIG(progressbar)
+#include <qprogressbar.h>
+#endif
+#if QT_CONFIG(pushbutton)
+#include <qpushbutton.h>
+#endif
+#include <qradiobutton.h>
+#if QT_CONFIG(rubberband)
+#include <qrubberband.h>
+#endif
+#if QT_CONFIG(scrollbar)
+#include <qscrollbar.h>
+#endif
+#if QT_CONFIG(sizegrip)
+#include <qsizegrip.h>
+#endif
+#include <qstyleoption.h>
+#include <qtoolbar.h>
+#if QT_CONFIG(toolbutton)
+#include <qtoolbutton.h>
+#endif
+#if QT_CONFIG(treeview)
+#include <qtreeview.h>
+#endif
+#if QT_CONFIG(tableview)
+#include <qtableview.h>
+#endif
+#include <qoperatingsystemversion.h>
+#if QT_CONFIG(wizard)
+#include <qwizard.h>
+#endif
+#include <qdebug.h>
+#include <qlibrary.h>
+#if QT_CONFIG(datetimeedit)
+#include <qdatetimeedit.h>
+#endif
+#include <qmath.h>
+#include <QtWidgets/qgraphicsproxywidget.h>
+#if QT_CONFIG(graphicsview)
+#include <QtWidgets/qgraphicsview.h>
+#endif
+#include <QtCore/qvariant.h>
+#include <private/qstylehelper_p.h>
+#include <private/qstyleanimation_p.h>
+#include <qpa/qplatformfontdatabase.h>
+#include <qpa/qplatformtheme.h>
+#include <QtGui/private/qcoregraphics_p.h>
+
+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<QObject>());
+
+ 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<QPointer<QObject> > 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<TestContentBorderPositionFunction>(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<const QTreeView *>(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<QRegion *>(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 &region)
+{
+ 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<NSWindow*>(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<NSWindow*>(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<const QPushButton *>(widg))
+ ct = QStyle::CT_PushButton;
+#endif
+ else if (qobject_cast<const QRadioButton *>(widg))
+ ct = QStyle::CT_RadioButton;
+#if QT_CONFIG(checkbox)
+ else if (qobject_cast<const QCheckBox *>(widg))
+ ct = QStyle::CT_CheckBox;
+#endif
+#if QT_CONFIG(combobox)
+ else if (qobject_cast<const QComboBox *>(widg))
+ ct = QStyle::CT_ComboBox;
+#endif
+#if QT_CONFIG(toolbutton)
+ else if (qobject_cast<const QToolButton *>(widg))
+ ct = QStyle::CT_ToolButton;
+#endif
+ else if (qobject_cast<const QSlider *>(widg))
+ ct = QStyle::CT_Slider;
+#if QT_CONFIG(progressbar)
+ else if (qobject_cast<const QProgressBar *>(widg))
+ ct = QStyle::CT_ProgressBar;
+#endif
+#if QT_CONFIG(lineedit)
+ else if (qobject_cast<const QLineEdit *>(widg))
+ ct = QStyle::CT_LineEdit;
+#endif
+ else if (qobject_cast<const QHeaderView *>(widg))
+ ct = QStyle::CT_HeaderSection;
+#if QT_CONFIG(menubar)
+ else if (qobject_cast<const QMenuBar *>(widg))
+ ct = QStyle::CT_MenuBar;
+#endif
+#if QT_CONFIG(sizegrip)
+ else if (qobject_cast<const QSizeGrip *>(widg))
+ ct = QStyle::CT_SizeGrip;
+#endif
+ else
+ return ret;
+ }
+
+ switch (ct) {
+#if QT_CONFIG(pushbutton)
+ case QStyle::CT_PushButton: {
+ const QPushButton *psh = qobject_cast<const QPushButton *>(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<QRadioButton *>(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<QMdiSubWindow *>(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<const QToolButton *>(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<const QSlider *>(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<const QProgressBar *>(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<QComboBox *>(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<QMacStyle *>(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<const QDateTimeEdit *>(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<PtrHIShapeGetBounds>(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<QMacStylePrivate *>(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<QRgb *>(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<QRgb *>(colorlessImage.scanLine(y));
+ const QRgb *activeScanLine = reinterpret_cast<const QRgb *>(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<NotificationReceiver *>(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<NotificationReceiver *>(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<QMenu*>(w)
+#if QT_CONFIG(combobox)
+ || qobject_cast<QComboBoxPrivateContainer *>(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<QTabBar*>(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<QRubberBand*>(w)) {
+ rubber->setWindowOpacity(0.25);
+ rubber->setAttribute(Qt::WA_PaintOnScreen, false);
+ rubber->setAttribute(Qt::WA_NoSystemBackground, false);
+ }
+
+ if (qobject_cast<QScrollBar*>(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<QMenu*>(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<QComboBox *>(w)) {
+ if (!combo->isEditable()) {
+ if (QWidget *widget = combo->findChild<QComboBoxPrivateContainer *>())
+ widget->setWindowOpacity(1.0);
+ }
+ }
+#endif
+
+#if QT_CONFIG(tabbar)
+ if (qobject_cast<QTabBar*>(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<QRubberBand*>(w)) {
+ rubber->setWindowOpacity(1.0);
+ rubber->setAttribute(Qt::WA_PaintOnScreen, true);
+ rubber->setAttribute(Qt::WA_NoSystemBackground, true);
+ }
+
+ if (QFocusFrame *frame = qobject_cast<QFocusFrame *>(w))
+ frame->setAttribute(Qt::WA_NoSystemBackground, true);
+
+ QCommonStyle::unpolish(w);
+
+ if (qobject_cast<QScrollBar*>(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<const QMainWindow*>(widget->parentWidget())
+ && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
+ && qobject_cast<const QAbstractScrollArea *>(widget))
+ ret = 0;
+ else
+#endif
+ // The combo box popup has no frame.
+ if (qstyleoption_cast<const QStyleOptionComboBox *>(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<const QStyleOptionSlider *>(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<const QStyleOptionTab *>(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<SInt32>([NSScroller
+ scrollerWidthForControlSize:static_cast<NSControlSize>(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<const QStyleOptionTabBarBase *>(opt)) {
+ ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
+ } else
+#endif
+ {
+ ret = QEvent::MouseButtonRelease;
+ }
+ break;
+ case SH_ComboBox_Popup:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(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<const QTabWidget*>(w)) {
+ if (tab->documentMode()) {
+ ret = Qt::AlignLeft;
+ break;
+ }
+ }
+#endif
+#if QT_CONFIG(tabbar)
+ if (const QTabBar *tab = qobject_cast<const QTabBar*>(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<QStyleHintReturnMask*>(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<QStyleHintReturnMask *>(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<QStyleHintReturnMask*>(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<QMenu *>(w->parentWidget()))
+ mdi.menuType = kThemeMenuTypeHierarchical;
+ else
+#endif
+ mdi.menuType = kThemeMenuTypePopUp;
+ QCFType<HIShapeRef> 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<const QScrollBar *>(w) && w->parent() &&
+ qobject_cast<QAbstractScrollArea*>(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<QWidget *>(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<QMacStylePrivate *>(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<const QStyleOptionTabBarBase *>(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<const QStyleOptionFrame *>(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<QGroupBox *>(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<qreal>() << 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<const QStyleOptionHeader *>(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<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(static_cast<CGFloat>(pc.redF()),
+ static_cast<CGFloat>(pc.greenF()),
+ static_cast<CGFloat>(pc.blueF()),
+ static_cast<CGFloat>(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<CTFontRef> 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<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values,
+ numValues, NULL, NULL);
+ // U+2713: CHECK MARK
+ QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@"\u2713", attributes);
+ QCFType<CTLineRef> 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<QMacStylePrivate *>(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<const QStyleOptionFrame *>(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<const QStyleOptionFrame *>(opt)) {
+#if QT_CONFIG(lineedit)
+ if ((opt->state & State_HasFocus) && !qobject_cast<const QLineEdit*>(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<const QStyleOptionTabWidgetFrame *>(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<QTabBar*>(w->parentWidget())) {
+ const bool documentMode = tabBar->documentMode();
+ const QTabBarPrivate *tabBarPrivate = static_cast<QTabBarPrivate *>(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<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
+ switch (ce) {
+ case CE_HeaderSection:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(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<const QTableView *>(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<const QStyleOptionHeader *>(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<const QStyleOptionToolButton *>(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<const QStyleOptionButton *>(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<const QStyleOptionButton *>(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<CGFloat>(textColor.redF()), static_cast<CGFloat>(textColor.greenF()),
+ static_cast<CGFloat>(textColor.blueF()), static_cast<CGFloat>(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<const QStyleOptionComboBox *>(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<const QStyleOptionTab *>(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<const QStyleOptionTab *>(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<const QTabBar *>(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<CGFloat>(textColor.redF()), static_cast<CGFloat>(textColor.greenF()),
+ static_cast<CGFloat>(textColor.blueF()), static_cast<CGFloat>(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<const QDockWidget *>(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<HIShapeRef> 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<const QStyleOptionDockWidget *>(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<const QStyleOptionMenuItem *>(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<const QComboBox *>(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<const QStyleOptionMenuItem *>(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<const QStyleOptionMenuItem *>(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<const QStyleOptionMenuItem *>(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<const QStyleOptionProgressBar *>(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<QProgressStyleAnimation*>(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<const QStyleOptionRubberBand *>(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<const QStyleOptionToolBar *>(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<QMainWindow *>(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<const QStyleOptionViewItem *>(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<const QStyleOptionButton *>(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<const QStyleOptionHeader *>(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<HIShapeRef> 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<const QStyleOptionTabWidgetFrame *>(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<const QStyleOptionTabWidgetFrame *>(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<const QStyleOptionTabWidgetFrame *>(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<const QStyleOptionTab *>(opt)) {
+ QRect dummyIconRect;
+ d->tabLayout(tab, widget, &rect, &dummyIconRect);
+ }
+ break;
+ case SE_TabBarTabLeftButton:
+ case SE_TabBarTabRightButton:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(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<int>(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<const QComboBox*>(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<QToolBar *>(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<const QStyleOptionButton *>(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<const QStyleOptionSlider *>(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<const QFrame *>(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<const QStyleOptionGroupBox *>(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<const QStyleOptionTabWidgetFrame *>(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<const QStyleOptionDockWidget*>(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<const QDockWidget*>(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<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
+ switch (cc) {
+ case CC_Slider:
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(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<HIShapeRef> 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<QObject>(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<QStyle::State>(styleObject->property("_q_stylestate").value<QStyle::State::Int>());
+ 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<QStyle::State::Int>(slider->state));
+ styleObject->setProperty("_q_stylecontrols", static_cast<uint>(slider->activeSubControls));
+
+ QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(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<QScrollbarStyleAnimation *>(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<qreal>(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<qreal>(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<const QStyleOptionSpinBox *>(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<const QStyleOptionComboBox *>(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<const QStyleOptionTitleBar *>(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<HIShapeRef> 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<HIShapeRef> 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<HIShapeRef> 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<const QStyleOptionGroupBox *>(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<CGFloat>(textColor.redF()), static_cast<CGFloat>(textColor.greenF()),
+ static_cast<CGFloat>(textColor.blueF()), static_cast<CGFloat>(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<const QStyleOptionToolButton *>(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<QWindow *>();
+
+ 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<const QStyleOptionSlider *>(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<const QStyleOptionComboBox *>(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<const QStyleOptionSlider *>(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<const QStyleOptionSlider *>(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<const QStyleOptionTitleBar *>(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<const QStyleOptionSlider *>(opt)) {
+ HIThemeTrackDrawInfo tdi;
+ d->getSliderInfo(cc, slider, &tdi, widget);
+ HIRect macRect;
+ QCFType<HIShapeRef> 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<const QStyleOptionTitleBar *>(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<HIShapeRef> region;
+ QRect tmpRect = titlebar->rect;
+ HIRect titleRect = qt_hirectForQRect(tmpRect);
+ HIThemeGetWindowShape(&titleRect, &wdi, kWindowTitleBarRgn, &region);
+ 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, &region);
+ ptrHIShapeGetBounds(region, &titleRect);
+ ret = qt_qrectForHIRect(titleRect);
+ }
+ }
+ break;
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(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<const QStyleOptionGroupBox *>(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<const QStyleOptionSpinBox *>(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<const QStyleOptionSpinBox *>(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<const QStyleOptionTabWidgetFrame *>(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<const QStyleOptionTab *>(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<const QStyleOptionMenuItem *>(opt)) {
+ int maxpmw = mi->maxIconWidth;
+#if QT_CONFIG(combobox)
+ const QComboBox *comboBox = qobject_cast<const QComboBox *>(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<const QStyleOptionComboBox *>(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<const QStyleOptionHeader *>(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<const QStyleOptionSlider *>(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<const QStyleOptionViewItem *>(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<const QStyleOptionComboBox *>(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<const QStyleOptionButton *>(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<QGraphicsView *>(focusWidget)) {
+ QGraphicsItem *focusItem = graphicsView->scene() ? graphicsView->scene()->focusItem() : 0;
+ if (focusItem && focusItem->type() == QGraphicsProxyWidget::Type) {
+ QGraphicsProxyWidget *proxy = static_cast<QGraphicsProxyWidget *>(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<QMainWindow *>(top)) {
+ QWidget *central = static_cast<QMainWindow *>(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<QByteArray, QFont>::operator=(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFonts());
+}
+
+Q_GLOBAL_STATIC(FontHash, app_fonts)
+FontHash *qt_app_fonts_hash()
+{
+ return app_fonts();
+}
+*/
+QT_END_NAMESPACE
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index 9ce1a04d86..e12aeb900b 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -3968,10 +3968,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);
diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp
index 447c7b2aeb..86c824afdb 100644
--- a/src/widgets/util/qsystemtrayicon.cpp
+++ b/src/widgets/util/qsystemtrayicon.cpp
@@ -111,9 +111,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,
@@ -420,9 +418,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()
diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp
index 7d4498af5b..e70d096e04 100644
--- a/src/widgets/widgets/qcombobox.cpp
+++ b/src/widgets/widgets/qcombobox.cpp
@@ -67,6 +67,7 @@
#include <qabstractproxymodel.h>
#include <qstylehints.h>
#include <private/qguiapplication_p.h>
+#include <private/qhighdpiscaling_p.h>
#include <private/qapplication_p.h>
#include <private/qcombobox_p.h>
#include <private/qabstractitemmodel_p.h>
@@ -2582,7 +2583,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.
diff --git a/src/xml/doc/src/qtxml-index.qdoc b/src/xml/doc/src/qtxml-index.qdoc
index eb35903756..91f2515d60 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.
*/
diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp
index b781176e13..168e8c3cb4 100644
--- a/src/xml/sax/qxml.cpp
+++ b/src/xml/sax/qxml.cpp
@@ -1270,18 +1270,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/concurrent/qtconcurrentmap/BLACKLIST b/tests/auto/concurrent/qtconcurrentmap/BLACKLIST
index 7cd8961f6f..0320f61fab 100644
--- a/tests/auto/concurrent/qtconcurrentmap/BLACKLIST
+++ b/tests/auto/concurrent/qtconcurrentmap/BLACKLIST
@@ -1,2 +1,3 @@
[qFutureAssignmentLeak]
ci opensuse
+ci ubuntu-16.04
diff --git a/tests/auto/corelib/io/qdir/qdir.pro b/tests/auto/corelib/io/qdir/qdir.pro
index 4870922312..2252e71cd8 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 8dbac28183..9d47bb2884 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 6450e9af7b..a55989aacd 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/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp
index bfb14da8b8..cd13e2bd19 100644
--- a/tests/auto/corelib/io/qfile/tst_qfile.cpp
+++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp
@@ -1684,6 +1684,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");
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index 02b70c317e..87d5675e7a 100644
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -1186,7 +1186,7 @@ void tst_QFileInfo::fileTimes()
QCOMPARE(fileInfo.birthTime(), birthTime); // mustn't have changed
QVERIFY(readTime.isValid());
-#if defined(Q_OS_WINRT) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID)
+#if defined(Q_OS_WINRT) || defined(Q_OS_QNX) || (defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED))
noAccessTime = true;
#elif defined(Q_OS_WIN)
//In Vista the last-access timestamp is not updated when the file is accessed/touched (by default).
@@ -1623,7 +1623,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 154c7ec5bf..b05a876a52 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 945022a289..1c978953d6 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 a485788ec2..4923baa0ca 100644
--- a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp
+++ b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp
@@ -70,7 +70,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 fc7ab70d41..eeeb3bc6e2 100644
--- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
+++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp
@@ -78,7 +78,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 287ab30993..ac976e9b9c 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 658201e03a..f937d23fe2 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 7fdd00876f..ab1866fb2d 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 76462be376..6dbb8ddd0d 100644
--- a/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp
+++ b/tests/auto/corelib/io/qtemporarydir/tst_qtemporarydir.cpp
@@ -290,7 +290,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 e17cb05cd8..11a5d58dc8 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 2d87c2193b..dbc3d68e93 100644
--- a/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp
+++ b/tests/auto/corelib/io/qtemporaryfile/tst_qtemporaryfile.cpp
@@ -102,7 +102,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()) {
@@ -351,7 +351,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");
@@ -571,7 +571,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
@@ -780,7 +780,7 @@ void tst_QTemporaryFile::createNativeFile_data()
QTest::addColumn<bool>("valid");
QTest::addColumn<QByteArray>("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 e673278920..d8924c2d5f 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 5bfe133966..451f96339e 100644
--- a/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp
+++ b/tests/auto/corelib/kernel/qtranslator/tst_qtranslator.cpp
@@ -65,7 +65,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/serialization/qdatastream/qdatastream.pro b/tests/auto/corelib/serialization/qdatastream/qdatastream.pro
index 291b3eb611..25f8b889a0 100644
--- a/tests/auto/corelib/serialization/qdatastream/qdatastream.pro
+++ b/tests/auto/corelib/serialization/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/tools/qbytearray/qbytearray.pro b/tests/auto/corelib/tools/qbytearray/qbytearray.pro
index f59cdf3524..c2101b0611 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 012e591298..70c1222988 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 35a9af05f6..480e723f44 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 10398f1a99..527e07593c 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 7fead5938b..8d3957a524 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/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
index 393e1b68aa..919f9cb718 100644
--- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
@@ -2267,6 +2267,7 @@ void tst_QDateTime::fromStringDateFormat_data()
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")
diff --git a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
index 62dd33131b..3e1668522e 100644
--- a/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
+++ b/tests/auto/corelib/tools/qsharedpointer/externaltests.cpp
@@ -42,6 +42,7 @@
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QLibraryInfo>
+#include <QtCore/QThread>
#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();
diff --git a/tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro b/tests/auto/corelib/tools/qtextboundaryfinder/qtextboundaryfinder.pro
index 8e0216b175..3c9f03842d 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/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp b/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp
index 20cd8caad3..80f22ad867 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());
diff --git a/tests/auto/gui/image/qimage/qimage.pro b/tests/auto/gui/image/qimage/qimage.pro
index 39ce4e26cb..56618e0bfa 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 3d35bf59da..b06f56dddf 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 34adedd187..e63e57886c 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/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST
index 4469b98953..05cf1b5a30 100644
--- a/tests/auto/gui/kernel/qwindow/BLACKLIST
+++ b/tests/auto/gui/kernel/qwindow/BLACKLIST
@@ -1,5 +1,5 @@
[positioning:default]
-ubuntu-16.04
+linux
osx-10.12 ci
[positioning:fake]
osx-10.12 ci
diff --git a/tests/auto/gui/painting/qpainter/qpainter.pro b/tests/auto/gui/painting/qpainter/qpainter.pro
index 0d3899ee92..9ccf8f20ba 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/gui/text/qrawfont/tst_qrawfont.cpp b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp
index 37f94d0278..373ad7fef9 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<bool>("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)
diff --git a/tests/auto/network/access/qftp/tst_qftp.cpp b/tests/auto/network/access/qftp/tst_qftp.cpp
index d42702e1de..1620c2ade6 100644
--- a/tests/auto/network/access/qftp/tst_qftp.cpp
+++ b/tests/auto/network/access/qftp/tst_qftp.cpp
@@ -43,6 +43,7 @@
#include <QtNetwork/private/qnetworksession_p.h>
#include <QTcpServer>
#include <QHostInfo>
+#include <QTcpSocket>
#include "../../../network-settings.h"
diff --git a/tests/auto/network/access/qnetworkreply/BLACKLIST b/tests/auto/network/access/qnetworkreply/BLACKLIST
index 4410549f09..7ffc2797cc 100644
--- a/tests/auto/network/access/qnetworkreply/BLACKLIST
+++ b/tests/auto/network/access/qnetworkreply/BLACKLIST
@@ -18,6 +18,9 @@ windows
windows
[ioPostToHttpFromSocket]
windows
+# QTBUG-66247
+[ioHttpRedirect]
+windows
[ioHttpRedirectMultipartPost]
linux
[ioHttpRedirectPolicy]
diff --git a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
index 31f82539aa..161d94d642 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());
diff --git a/tests/auto/network/socket/qtcpsocket/BLACKLIST b/tests/auto/network/socket/qtcpsocket/BLACKLIST
index 96e59e5678..d724897b74 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
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 5842d58fab..b8d19c0c0d 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/tools/qmakelib/evaltest.cpp b/tests/auto/tools/qmakelib/evaltest.cpp
index 387a2fb84e..786b9e72f1 100644
--- a/tests/auto/tools/qmakelib/evaltest.cpp
+++ b/tests/auto/tools/qmakelib/evaltest.cpp
@@ -34,6 +34,12 @@
#include <qmakeglobals.h>
#include <qmakeevaluator.h>
+#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;
@@ -2593,20 +2615,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 b1250f4f1a..4a4b20fe50 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<QString>("path");
+ QTest::addColumn<bool>("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 }
+ };
+
+ 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<QString>("base");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QString>("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);
- QString fnbase = "/another/dir";
- QCOMPARE(IoUtils::resolvePath(fnbase, fn0), QStringLiteral("/another/dir/file/path"));
- QCOMPARE(IoUtils::resolvePath(fnbase, fn1), QStringLiteral("/a/unix/file/path"));
+ 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 e75dedb7ec..acfeb43ecd 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();
diff --git a/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST b/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST
index 36e47830d0..da52809aad 100644
--- a/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST
+++ b/tests/auto/widgets/dialogs/qmessagebox/BLACKLIST
@@ -1,2 +1,2 @@
[defaultButton]
-osx ci
+*
diff --git a/tests/auto/widgets/dialogs/qsidebar/tst_qsidebar.cpp b/tests/auto/widgets/dialogs/qsidebar/tst_qsidebar.cpp
index 78d0372ac0..3c189f92cc 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 539580f628..3b340d06ab 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 3527b424c1..0429315d95 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 2044704e76..48d39bbb11 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/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
index a5d131a436..3594e7fa01 100644
--- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
+++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
@@ -2262,10 +2262,6 @@ void tst_QHeaderView::QTBUG6058_reset()
void tst_QHeaderView::QTBUG7833_sectionClicked()
{
-
-
-
-
QTableView tv;
QStandardItemModel *sim = new QStandardItemModel(&tv);
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(&tv);
@@ -2289,11 +2285,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)));
diff --git a/tests/auto/widgets/kernel/qlayout/qlayout.pro b/tests/auto/widgets/kernel/qlayout/qlayout.pro
index 8e0ea1bfdb..e768e19a26 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 a55693bb6c..300a8878ba 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 0fb7499946..9ad0940245 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
}
diff --git a/tests/auto/widgets/widgets/qmenubar/BLACKLIST b/tests/auto/widgets/widgets/qmenubar/BLACKLIST
index b3bf606a08..9b8e07312d 100644
--- a/tests/auto/widgets/widgets/qmenubar/BLACKLIST
+++ b/tests/auto/widgets/widgets/qmenubar/BLACKLIST
@@ -1,2 +1,5 @@
[check_menuPosition]
ubuntu-16.04
+#QTBUG-66255
+[activatedCount]
+*
diff --git a/tests/auto/widgets/widgets/qscrollbar/BLACKLIST b/tests/auto/widgets/widgets/qscrollbar/BLACKLIST
new file mode 100644
index 0000000000..277ae4d260
--- /dev/null
+++ b/tests/auto/widgets/widgets/qscrollbar/BLACKLIST
@@ -0,0 +1,3 @@
+#QTBUG-66321
+[QTBUG_42871]
+macos
diff --git a/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp b/tests/auto/xml/sax/qxmlinputsource/tst_qxmlinputsource.cpp
index c5e9a44398..752e39c23f 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("<foo><bar>kake</bar><bar>ja</bar></foo>");
+ 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"