summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2018-06-30 22:59:21 +0200
committerLiang Qi <liang.qi@qt.io>2018-07-02 11:23:45 +0200
commite3ed2281c0c891cf3b15c95f9f7cdae42e9f233a (patch)
treeaae8da6ce616eae02b69fb1fcdcb4383c8fe6811 /src
parent3be141d5bc199080b524d8f6f5ce514e8f74d23a (diff)
parente75e4b39b78ba05ea2cd45dc96acf99fc89c5915 (diff)
Merge remote-tracking branch 'origin/5.11' into dev
Conflicts: src/plugins/platforms/cocoa/qnsview.mm src/plugins/platforms/cocoa/qnsview_dragging.mm src/plugins/platforms/ios/qiosinputcontext.mm src/plugins/platforms/xcb/qxcbconnection.cpp src/plugins/platforms/xcb/qxcbconnection_xi2.cpp src/plugins/platforms/xcb/qxcbwindow.cpp src/tools/androiddeployqt/main.cpp Was moved from qttools into qtbase in 5.11. So re-apply 32398e4d here. tests/auto/corelib/global/qlogging/test/test.pro tests/auto/corelib/global/qlogging/tst_qlogging.cpp tests/auto/corelib/io/qfile/tst_qfile.cpp tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp tests/auto/corelib/thread/qthreadstorage/test/test.pro tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp tests/auto/widgets/kernel/qapplication/test/test.pro Done-with: Gatis Paeglis <gatis.paeglis@qt.io> Done-with: MÃ¥rten Nordheim <marten.nordheim@qt.io> Done-with: Oliver Wolff <oliver.wolff@qt.io> Change-Id: Id970486c5315a1718c540f00deb2633533e8fc7b
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h2
-rw-r--r--src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch31
-rw-r--r--src/concurrent/doc/src/qtconcurrent-module.qdoc2
-rw-r--r--src/corelib/Qt5CoreMacros.cmake51
-rw-r--r--src/corelib/animation/qpropertyanimation.cpp2
-rw-r--r--src/corelib/global/qcompilerdetection.h2
-rw-r--r--src/corelib/global/qglobal.cpp5
-rw-r--r--src/corelib/global/qglobalstatic.qdoc32
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp8
-rw-r--r--src/corelib/global/qoperatingsystemversion.h1
-rw-r--r--src/corelib/global/qoperatingsystemversion_win.cpp2
-rw-r--r--src/corelib/global/qsystemdetection.h79
-rw-r--r--src/corelib/io/qdebug.cpp2
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp3
-rw-r--r--src/corelib/io/qlockfile_win.cpp5
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp18
-rw-r--r--src/corelib/itemmodels/qidentityproxymodel.cpp2
-rw-r--r--src/corelib/kernel/kernel.pri2
-rw-r--r--src/corelib/kernel/qcore_mac_objc.mm41
-rw-r--r--src/corelib/kernel/qcore_mac_p.h11
-rw-r--r--src/corelib/kernel/qdeadlinetimer.cpp5
-rw-r--r--src/corelib/kernel/qmetatype.h4
-rw-r--r--src/corelib/kernel/qobject.cpp2
-rw-r--r--src/corelib/kernel/qtimer.cpp2
-rw-r--r--src/corelib/serialization/qdatastream.h4
-rw-r--r--src/corelib/serialization/qxmlstream.cpp2
-rw-r--r--src/corelib/thread/qfuture.qdoc30
-rw-r--r--src/corelib/thread/qfuturesynchronizer.qdoc30
-rw-r--r--src/corelib/thread/qsemaphore.cpp2
-rw-r--r--src/corelib/tools/qbytearray.cpp40
-rw-r--r--src/corelib/tools/qbytearraymatcher.cpp7
-rw-r--r--src/corelib/tools/qlocale.cpp112
-rw-r--r--src/corelib/tools/qsharedpointer.cpp6
-rw-r--r--src/corelib/tools/qstring.cpp109
-rw-r--r--src/corelib/tools/qstringiterator.qdoc30
-rw-r--r--src/corelib/tools/qtimezoneprivate_android.cpp19
-rw-r--r--src/corelib/tools/qvector.qdoc30
-rw-r--r--src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp212
-rw-r--r--src/dbus/doc/src/dbus-adaptors.qdoc132
-rw-r--r--src/dbus/qdbusabstractinterface.cpp2
-rw-r--r--src/dbus/qdbuspendingcall.cpp4
-rw-r--r--src/dbus/qdbuspendingreply.cpp2
-rw-r--r--src/gui/itemmodels/qstandarditemmodel.cpp8
-rw-r--r--src/gui/itemmodels/qstandarditemmodel_p.h44
-rw-r--r--src/gui/kernel/qguiapplication.cpp14
-rw-r--r--src/gui/kernel/qpixelformat.cpp2
-rw-r--r--src/gui/kernel/qrasterwindow.cpp2
-rw-r--r--src/gui/kernel/qwindow.cpp2
-rw-r--r--src/gui/opengl/qopenglfunctions_es2.cpp2
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp38
-rw-r--r--src/gui/painting/qmatrix.cpp12
-rw-r--r--src/gui/painting/qpagesize.cpp2
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp2
-rw-r--r--src/gui/painting/qtransform.cpp18
-rw-r--r--src/gui/text/qplatformfontdatabase.cpp2
-rw-r--r--src/network/access/access.pri13
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp2
-rw-r--r--src/network/access/qnetworkcookiejar.cpp2
-rw-r--r--src/network/access/qnetworkreply.cpp2
-rw-r--r--src/network/doc/src/qtnetwork.qdoc2
-rw-r--r--src/network/kernel/qauthenticator.cpp4
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp2
-rw-r--r--src/network/ssl/qsslconfiguration.cpp2
-rw-r--r--src/network/ssl/qsslsocket_openssl11.cpp9
-rw-r--r--src/network/ssl/qsslsocket_opensslpre11.cpp9
-rw-r--r--src/platformheaders/nativecontexts/qeglnativecontext.qdoc2
-rw-r--r--src/platformheaders/nativecontexts/qwglnativecontext.qdoc2
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp2
-rw-r--r--src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp14
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp2
-rw-r--r--src/platformsupport/platformsupport.pro2
-rw-r--r--src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp9
-rw-r--r--src/platformsupport/themes/themes.pro2
-rw-r--r--src/plugins/imageformats/ico/ico.json2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm7
-rw-r--r--src/plugins/platforms/cocoa/qnsview_dragging.mm6
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm35
-rw-r--r--src/plugins/platforms/ios/kernel.pro2
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.mm4
-rw-r--r--src/plugins/platforms/ios/qiosfiledialog.mm4
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm14
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm9
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm2
-rw-r--r--src/plugins/platforms/ios/qiosmessagedialog.mm4
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm33
-rw-r--r--src/plugins/platforms/ios/qiosservices.mm25
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm8
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm3
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm10
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.h2
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp40
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp92
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.h9
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp28
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h11
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp107
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp36
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp7
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp7
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp8
-rw-r--r--src/plugins/sqldrivers/ibase/qsql_ibase.cpp12
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm31
-rw-r--r--src/plugins/styles/windowsvista/qwindowsxpstyle.cpp4
-rw-r--r--src/src.pro10
-rw-r--r--src/testlib/qabstractitemmodeltester.cpp24
-rw-r--r--src/testlib/qabstractitemmodeltester.h2
-rw-r--r--src/testlib/qtestcase.cpp11
-rw-r--r--src/tools/androiddeployqt/androiddeployqt.pro14
-rw-r--r--src/tools/androiddeployqt/main.cpp2912
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp43
-rw-r--r--src/widgets/graphicsview/qgraphicsitem.cpp2
-rw-r--r--src/widgets/itemviews/qheaderview.cpp2
-rw-r--r--src/widgets/kernel/qwidget.cpp3
-rw-r--r--src/widgets/widgets/qmenubar.cpp11
-rw-r--r--src/widgets/widgets/qplaintextedit.cpp2
-rw-r--r--src/widgets/widgets/qtextedit.cpp2
121 files changed, 3937 insertions, 998 deletions
diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h
index 3cc860d753..dc870f626f 100644
--- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h
+++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h
@@ -83,7 +83,7 @@ class MacroExpander : public Lexer
Diagnostics *mDiagnostics;
bool mParseDefined;
- std::auto_ptr<Token> mReserveToken;
+ std::unique_ptr<Token> mReserveToken;
std::vector<MacroContext *> mContextStack;
};
diff --git a/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch b/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch
new file mode 100644
index 0000000000..314a985bab
--- /dev/null
+++ b/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch
@@ -0,0 +1,31 @@
+From 946903d23ae361ddb05d2c0f64b339eb1694311b Mon Sep 17 00:00:00 2001
+From: Corentin Wallez <cwallez@chromium.org>
+Date: Mon, 18 Apr 2016 17:30:07 -0400
+Subject: [PATCH] Remove usage of auto_ptr in MacroExpander
+
+BUG=angleproject:1269
+
+Change-Id: I1fafa102b065f6da1797e8790ec3ed498d9d8b45
+Reviewed-on: https://chromium-review.googlesource.com/339379
+Reviewed-by: Jamie Madill <jmadill@chromium.org>
+Commit-Queue: Corentin Wallez <cwallez@chromium.org>
+---
+ src/compiler/preprocessor/MacroExpander.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/compiler/preprocessor/MacroExpander.h b/src/compiler/preprocessor/MacroExpander.h
+index 3cc860d75..dc870f626 100644
+--- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h
++++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h
+@@ -83,7 +83,7 @@ class MacroExpander : public Lexer
+ Diagnostics *mDiagnostics;
+ bool mParseDefined;
+
+- std::auto_ptr<Token> mReserveToken;
++ std::unique_ptr<Token> mReserveToken;
+ std::vector<MacroContext *> mContextStack;
+ };
+
+--
+2.15.0.windows.1
+
diff --git a/src/concurrent/doc/src/qtconcurrent-module.qdoc b/src/concurrent/doc/src/qtconcurrent-module.qdoc
index 7f2b9b9562..9289b4bfa8 100644
--- a/src/concurrent/doc/src/qtconcurrent-module.qdoc
+++ b/src/concurrent/doc/src/qtconcurrent-module.qdoc
@@ -28,7 +28,7 @@
/*!
\module QtConcurrent
\title Qt Concurrent C++ Classes
- \brief The Qt Concurrent module contains functionality to support concurrent execution of program code
+ \brief The Qt Concurrent module contains functionality to support concurrent execution of program code.
\ingroup modules
\qtvariable concurrent
diff --git a/src/corelib/Qt5CoreMacros.cmake b/src/corelib/Qt5CoreMacros.cmake
index 1627de4002..819b48f973 100644
--- a/src/corelib/Qt5CoreMacros.cmake
+++ b/src/corelib/Qt5CoreMacros.cmake
@@ -294,3 +294,54 @@ function(QT5_ADD_RESOURCES outfiles )
endfunction()
set(_Qt5_COMPONENT_PATH "${CMAKE_CURRENT_LIST_DIR}/..")
+
+if (NOT CMAKE_VERSION VERSION_LESS 2.8.9)
+ macro(qt5_use_modules _target _link_type)
+ if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.11)
+ if(CMAKE_WARN_DEPRECATED)
+ set(messageType WARNING)
+ endif()
+ if(CMAKE_ERROR_DEPRECATED)
+ set(messageType FATAL_ERROR)
+ endif()
+ if(messageType)
+ message(${messageType} "The qt5_use_modules macro is obsolete. Use target_link_libraries with IMPORTED targets instead.")
+ endif()
+ endif()
+
+ if (NOT TARGET ${_target})
+ message(FATAL_ERROR "The first argument to qt5_use_modules must be an existing target.")
+ endif()
+ if ("${_link_type}" STREQUAL "LINK_PUBLIC" OR "${_link_type}" STREQUAL "LINK_PRIVATE" )
+ set(_qt5_modules ${ARGN})
+ set(_qt5_link_type ${_link_type})
+ else()
+ set(_qt5_modules ${_link_type} ${ARGN})
+ endif()
+
+ if ("${_qt5_modules}" STREQUAL "")
+ message(FATAL_ERROR "qt5_use_modules requires at least one Qt module to use.")
+ endif()
+
+ foreach(_module ${_qt5_modules})
+ if (NOT Qt5${_module}_FOUND)
+ find_package(Qt5${_module} PATHS "${_Qt5_COMPONENT_PATH}" NO_DEFAULT_PATH)
+ if (NOT Qt5${_module}_FOUND)
+ message(FATAL_ERROR "Can not use \"${_module}\" module which has not yet been found.")
+ endif()
+ endif()
+ target_link_libraries(${_target} ${_qt5_link_type} ${Qt5${_module}_LIBRARIES})
+ set_property(TARGET ${_target} APPEND PROPERTY INCLUDE_DIRECTORIES ${Qt5${_module}_INCLUDE_DIRS})
+ set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS ${Qt5${_module}_COMPILE_DEFINITIONS})
+ set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG)
+ set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO QT_NO_DEBUG)
+ set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_MINSIZEREL QT_NO_DEBUG)
+ if (Qt5_POSITION_INDEPENDENT_CODE
+ AND (CMAKE_VERSION VERSION_LESS 2.8.12
+ AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
+ OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)))
+ set_property(TARGET ${_target} PROPERTY POSITION_INDEPENDENT_CODE ${Qt5_POSITION_INDEPENDENT_CODE})
+ endif()
+ endforeach()
+ endmacro()
+endif()
diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp
index 9fd845bb93..5ba2a1fa73 100644
--- a/src/corelib/animation/qpropertyanimation.cpp
+++ b/src/corelib/animation/qpropertyanimation.cpp
@@ -40,7 +40,7 @@
/*!
\class QPropertyAnimation
\inmodule QtCore
- \brief The QPropertyAnimation class animates Qt properties
+ \brief The QPropertyAnimation class animates Qt properties.
\since 4.6
\ingroup animation
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 87ade23503..9906425f5b 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -629,7 +629,7 @@
# define Q_COMPILER_THREAD_LOCAL
# define Q_COMPILER_UDL
# endif
-# elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L s
+# elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L
// C11 features supported. Only tested with ICC 17 and up.
# define Q_COMPILER_STATIC_ASSERT
# if __has_include(<threads.h>)
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index b654f5863a..3fe91cae65 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -1038,6 +1038,11 @@ Q_STATIC_ASSERT((std::is_same<qsizetype, qptrdiff>::value));
\snippet code/src_corelib_global_qglobal.cpp 53
+ \note Qt detects the necessary C++14 compiler support by way of the feature
+ test recommendations from
+ \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations}
+ {C++ Committee's Standing Document 6}.
+
\sa qConstOverload(), qNonConstOverload(), {Differences between String-Based
and Functor-Based Connections}
*/
diff --git a/src/corelib/global/qglobalstatic.qdoc b/src/corelib/global/qglobalstatic.qdoc
index 63cc968d1c..303709bb1d 100644
--- a/src/corelib/global/qglobalstatic.qdoc
+++ b/src/corelib/global/qglobalstatic.qdoc
@@ -3,9 +3,9 @@
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtCore module of the Qt Toolkit.
+** This file is part of the documentation of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,25 +14,13 @@
** 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.
-**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -336,7 +324,7 @@
\threadsafe
\inmodule QtCore
\since 5.1
- \brief The QGlobalStatic class is used to implement a global static object
+ \brief The QGlobalStatic class is used to implement a global static object.
The QGlobalStatic class is the front-end API exported when
Q_GLOBAL_STATIC() is used. See the documentation for the macro for a
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index 4d267e328d..2f8d339ca7 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -438,6 +438,14 @@ const QOperatingSystemVersion QOperatingSystemVersion::MacOSHighSierra =
QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 13);
/*!
+ \variable QOperatingSystemVersion::MacOSMojave
+ \brief a version corresponding to macOS Mojave (version 10.14).
+ \since 5.11.2
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::MacOSMojave =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 14);
+
+/*!
\variable QOperatingSystemVersion::AndroidJellyBean
\brief a version corresponding to Android Jelly Bean (version 4.1, API level 16).
\since 5.9
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
index 5f27deab9e..df01e5438a 100644
--- a/src/corelib/global/qoperatingsystemversion.h
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -70,6 +70,7 @@ public:
static const QOperatingSystemVersion OSXElCapitan;
static const QOperatingSystemVersion MacOSSierra;
static const QOperatingSystemVersion MacOSHighSierra;
+ static const QOperatingSystemVersion MacOSMojave;
static const QOperatingSystemVersion AndroidJellyBean;
static const QOperatingSystemVersion AndroidJellyBean_MR1;
diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp
index f3662ae1f9..7659fb2550 100644
--- a/src/corelib/global/qoperatingsystemversion_win.cpp
+++ b/src/corelib/global/qoperatingsystemversion_win.cpp
@@ -97,7 +97,7 @@ static inline OSVERSIONINFOEX determineWinOsVersion()
// because linking to it at load time will not pass the Windows App Certification Kit
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx
RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
- GetProcAddressA(ntdll, "RtlGetVersion"));
+ reinterpret_cast<QFunctionPointer>(GetProcAddressA(ntdll, "RtlGetVersion")));
if (Q_UNLIKELY(!pRtlGetVersion))
return result;
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index ff0e03108b..cacb95b674 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -216,18 +216,6 @@
# // Numerical checks are preferred to named checks, but to be safe
# // we define the missing version names in case Qt uses them.
#
-# if !defined(__MAC_10_7)
-# define __MAC_10_7 1070
-# endif
-# if !defined(__MAC_10_8)
-# define __MAC_10_8 1080
-# endif
-# if !defined(__MAC_10_9)
-# define __MAC_10_9 1090
-# endif
-# if !defined(__MAC_10_10)
-# define __MAC_10_10 101000
-# endif
# if !defined(__MAC_10_11)
# define __MAC_10_11 101100
# endif
@@ -237,17 +225,8 @@
# if !defined(__MAC_10_13)
# define __MAC_10_13 101300
# endif
-# if !defined(MAC_OS_X_VERSION_10_7)
-# define MAC_OS_X_VERSION_10_7 1070
-# endif
-# if !defined(MAC_OS_X_VERSION_10_8)
-# define MAC_OS_X_VERSION_10_8 1080
-# endif
-# if !defined(MAC_OS_X_VERSION_10_9)
-# define MAC_OS_X_VERSION_10_9 1090
-# endif
-# if !defined(MAC_OS_X_VERSION_10_10)
-# define MAC_OS_X_VERSION_10_10 101000
+# if !defined(__MAC_10_14)
+# define __MAC_10_14 101400
# endif
# if !defined(MAC_OS_X_VERSION_10_11)
# define MAC_OS_X_VERSION_10_11 101100
@@ -258,55 +237,10 @@
# if !defined(MAC_OS_X_VERSION_10_13)
# define MAC_OS_X_VERSION_10_13 101300
# endif
-#
-# if !defined(__IPHONE_4_3)
-# define __IPHONE_4_3 40300
-# endif
-# if !defined(__IPHONE_5_0)
-# define __IPHONE_5_0 50000
-# endif
-# if !defined(__IPHONE_5_1)
-# define __IPHONE_5_1 50100
-# endif
-# if !defined(__IPHONE_6_0)
-# define __IPHONE_6_0 60000
-# endif
-# if !defined(__IPHONE_6_1)
-# define __IPHONE_6_1 60100
-# endif
-# if !defined(__IPHONE_7_0)
-# define __IPHONE_7_0 70000
-# endif
-# if !defined(__IPHONE_7_1)
-# define __IPHONE_7_1 70100
-# endif
-# if !defined(__IPHONE_8_0)
-# define __IPHONE_8_0 80000
-# endif
-# if !defined(__IPHONE_8_1)
-# define __IPHONE_8_1 80100
-# endif
-# if !defined(__IPHONE_8_2)
-# define __IPHONE_8_2 80200
-# endif
-# if !defined(__IPHONE_8_3)
-# define __IPHONE_8_3 80300
-# endif
-# if !defined(__IPHONE_8_4)
-# define __IPHONE_8_4 80400
-# endif
-# if !defined(__IPHONE_9_0)
-# define __IPHONE_9_0 90000
-# endif
-# if !defined(__IPHONE_9_1)
-# define __IPHONE_9_1 90100
-# endif
-# if !defined(__IPHONE_9_2)
-# define __IPHONE_9_2 90200
-# endif
-# if !defined(__IPHONE_9_3)
-# define __IPHONE_9_3 90300
+# if !defined(MAC_OS_X_VERSION_10_14)
+# define MAC_OS_X_VERSION_10_14 101400
# endif
+#
# if !defined(__IPHONE_10_0)
# define __IPHONE_10_0 100000
# endif
@@ -322,6 +256,9 @@
# if !defined(__IPHONE_11_0)
# define __IPHONE_11_0 110000
# endif
+# if !defined(__IPHONE_12_0)
+# define __IPHONE_12_0 120000
+# endif
#endif
#ifdef __LSB_VERSION__
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 0d9a6c8749..013d531581 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -842,7 +842,7 @@ QDebug &QDebug::resetFormat()
/*!
\class QDebugStateSaver
\inmodule QtCore
- \brief Convenience class for custom QDebug operators
+ \brief Convenience class for custom QDebug operators.
Saves the settings used by QDebug, and restores them upon destruction,
then calls \l {QDebug::maybeSpace()}{maybeSpace()}, to separate arguments with a space if
diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp
index 048669b92f..c0c5f9d744 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp
@@ -302,7 +302,8 @@ QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths,
| IN_DELETE_SELF
)));
if (wd < 0) {
- qWarning().nospace() << "inotify_add_watch(" << path << ") failed: " << QSystemError(errno, QSystemError::NativeError).toString();
+ if (errno != ENOENT)
+ qErrnoWarning("inotify_add_watch(%ls) failed:", path.constData());
continue;
}
diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp
index 6b8028460c..277f8d4230 100644
--- a/src/corelib/io/qlockfile_win.cpp
+++ b/src/corelib/io/qlockfile_win.cpp
@@ -153,9 +153,8 @@ QString QLockFilePrivate::processNameByPid(qint64 pid)
HMODULE hPsapi = LoadLibraryA("psapi");
if (!hPsapi)
return QString();
-
- GetModuleFileNameExFunc qGetModuleFileNameEx
- = (GetModuleFileNameExFunc)GetProcAddress(hPsapi, "GetModuleFileNameExW");
+ GetModuleFileNameExFunc qGetModuleFileNameEx = reinterpret_cast<GetModuleFileNameExFunc>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(hPsapi, "GetModuleFileNameExW")));
if (!qGetModuleFileNameEx) {
FreeLibrary(hPsapi);
return QString();
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index d826110ec7..3a6f67521f 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -182,8 +182,8 @@ QPersistentModelIndex::~QPersistentModelIndex()
Returns \c{true} if this persistent model index is equal to the \a other
persistent model index; otherwise returns \c{false}.
- All values in the persistent model index are used when comparing
- with another persistent model index.
+ The internal data pointer, row, column, and model values in the persistent
+ model index are used when comparing with another persistent model index.
*/
bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const
@@ -199,8 +199,8 @@ bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const
Returns \c{true} if this persistent model index is smaller than the \a other
persistent model index; otherwise returns \c{false}.
- All values in the persistent model index are used when comparing
- with another persistent model index.
+ The internal data pointer, row, column, and model values in the persistent
+ model index are used when comparing with another persistent model index.
*/
bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const
@@ -275,13 +275,11 @@ QPersistentModelIndex::operator const QModelIndex&() const
}
/*!
- \fn bool QPersistentModelIndex::operator==(const QModelIndex &other) const
-
Returns \c{true} if this persistent model index refers to the same location as
the \a other model index; otherwise returns \c{false}.
- All values in the persistent model index are used when comparing with
- another model index.
+ The internal data pointer, row, column, and model values in the persistent
+ model index are used when comparing with another model index.
*/
bool QPersistentModelIndex::operator==(const QModelIndex &other) const
@@ -1167,8 +1165,8 @@ void QAbstractItemModel::resetInternalData()
Returns \c{true} if this model index refers to the same location as the
\a other model index; otherwise returns \c{false}.
- All values in the model index are used when comparing with another model
- index.
+ The internal data pointer, row, column, and model values are used when
+ comparing with another model index.
*/
diff --git a/src/corelib/itemmodels/qidentityproxymodel.cpp b/src/corelib/itemmodels/qidentityproxymodel.cpp
index e984ec194e..c1e23dbd0c 100644
--- a/src/corelib/itemmodels/qidentityproxymodel.cpp
+++ b/src/corelib/itemmodels/qidentityproxymodel.cpp
@@ -83,7 +83,7 @@ class QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate
\since 4.8
\class QIdentityProxyModel
\inmodule QtCore
- \brief The QIdentityProxyModel class proxies its source model unmodified
+ \brief The QIdentityProxyModel class proxies its source model unmodified.
\ingroup model-view
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index ca8bd30698..c528b16f9c 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -120,7 +120,7 @@ mac {
LIBS_PRIVATE += -framework Foundation
- osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit
+ osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit -framework Security
ios|tvos {
# We need UIKit for UIApplication in qeventdispatcher_cf.mm
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm
index 97a3acacd2..0d7bfad943 100644
--- a/src/corelib/kernel/qcore_mac_objc.mm
+++ b/src/corelib/kernel/qcore_mac_objc.mm
@@ -44,6 +44,10 @@
#include <AppKit/NSText.h>
#endif
+#if defined(QT_PLATFORM_UIKIT)
+#include <UIKit/UIKit.h>
+#endif
+
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@@ -190,6 +194,43 @@ AppleApplication *qt_apple_sharedApplication()
}
#endif
+#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED)
+bool qt_apple_isSandboxed()
+{
+ static bool isSandboxed = []() {
+ QCFType<SecStaticCodeRef> staticCode = nullptr;
+ NSURL *bundleUrl = [[NSBundle mainBundle] bundleURL];
+ if (SecStaticCodeCreateWithPath((__bridge CFURLRef)bundleUrl,
+ kSecCSDefaultFlags, &staticCode) != errSecSuccess)
+ return false;
+
+ QCFType<SecRequirementRef> sandboxRequirement;
+ if (SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"),
+ kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess)
+ return false;
+
+ if (SecStaticCodeCheckValidityWithErrors(staticCode,
+ kSecCSBasicValidateOnly, sandboxRequirement, nullptr) != errSecSuccess)
+ return false;
+
+ return true;
+ }();
+ return isSandboxed;
+}
+
+QT_END_NAMESPACE
+@implementation NSObject (QtSandboxHelpers)
+- (id)qt_valueForPrivateKey:(NSString *)key
+{
+ if (qt_apple_isSandboxed())
+ return nil;
+
+ return [self valueForKey:key];
+}
+@end
+QT_BEGIN_NAMESPACE
+#endif
+
#ifdef Q_OS_MACOS
/*
Ensure that Objective-C objects auto-released in main(), directly or indirectly,
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 84978bbbc3..1161e363b7 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -192,6 +192,17 @@ QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool);
Q_CORE_EXPORT void qt_apple_check_os_version();
Q_CORE_EXPORT bool qt_apple_isApplicationExtension();
+#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED)
+Q_CORE_EXPORT bool qt_apple_isSandboxed();
+# ifdef __OBJC__
+QT_END_NAMESPACE
+@interface NSObject (QtSandboxHelpers)
+- (id)qt_valueForPrivateKey:(NSString *)key;
+@end
+QT_BEGIN_NAMESPACE
+# endif
+#endif
+
#if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS)
QT_END_NAMESPACE
# if defined(Q_OS_MACOS)
diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp
index 97b98a1376..4fba30050d 100644
--- a/src/corelib/kernel/qdeadlinetimer.cpp
+++ b/src/corelib/kernel/qdeadlinetimer.cpp
@@ -344,6 +344,11 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time
deadline.setRemainingTime(250ms);
\endcode
+ \note Qt detects the necessary C++14 compiler support by way of the feature
+ test recommendations from
+ \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations}
+ {C++ Committee's Standing Document 6}.
+
\sa setDeadline(), remainingTime(), hasExpired(), isForever()
*/
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index a0969ee908..cf68752f85 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -1413,8 +1413,8 @@ namespace QtPrivate
static char checkType(void (X::*)());
static void *checkType(void (T::*)());
enum {
- IsRealGadget = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
- IsGadgetOrDerivedFrom = true
+ IsRealGadget = !IsPointerToTypeDerivedFromQObject<T*>::Value && sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *),
+ IsGadgetOrDerivedFrom = !IsPointerToTypeDerivedFromQObject<T*>::Value
};
};
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 3717d7a19e..5387d549c6 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -511,7 +511,7 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
/*!
\class QSignalBlocker
- \brief Exception-safe wrapper around QObject::blockSignals()
+ \brief Exception-safe wrapper around QObject::blockSignals().
\since 5.3
\ingroup objectmodel
\inmodule QtCore
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp
index 802c8d72f6..d8d520ff58 100644
--- a/src/corelib/kernel/qtimer.cpp
+++ b/src/corelib/kernel/qtimer.cpp
@@ -117,7 +117,7 @@ QT_BEGIN_NAMESPACE
All timer types may time out later than expected if the system is busy or
unable to provide the requested accuracy. In such a case of timeout
- overrun, Qt will emit activated() only once, even if multiple timeouts have
+ overrun, Qt will emit timeout() only once, even if multiple timeouts have
expired, and then will resume the original interval.
\section1 Alternatives to QTimer
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 4ae4a3d76c..eae0146553 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -152,7 +152,7 @@ public:
QDataStream &operator>>(qint16 &i);
QDataStream &operator>>(quint16 &i);
QDataStream &operator>>(qint32 &i);
- QDataStream &operator>>(quint32 &i);
+ inline QDataStream &operator>>(quint32 &i);
QDataStream &operator>>(qint64 &i);
QDataStream &operator>>(quint64 &i);
QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; }
@@ -168,7 +168,7 @@ public:
QDataStream &operator<<(qint16 i);
QDataStream &operator<<(quint16 i);
QDataStream &operator<<(qint32 i);
- QDataStream &operator<<(quint32 i);
+ inline QDataStream &operator<<(quint32 i);
QDataStream &operator<<(qint64 i);
QDataStream &operator<<(quint64 i);
QDataStream &operator<<(std::nullptr_t) { return *this; }
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index a92dd71df5..f18c4cc8e7 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -2265,7 +2265,7 @@ QXmlStreamAttributes QXmlStreamReader::attributes() const
\inmodule QtCore
\since 4.3
\reentrant
- \brief The QXmlStreamAttribute class represents a single XML attribute
+ \brief The QXmlStreamAttribute class represents a single XML attribute.
\ingroup xml-tools
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index e607d090c5..7db65dacd3 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -3,9 +3,9 @@
** 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.
+** This file is part of the documentation of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,25 +14,13 @@
** 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.
-**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/corelib/thread/qfuturesynchronizer.qdoc b/src/corelib/thread/qfuturesynchronizer.qdoc
index c9c402ff87..67dafb039e 100644
--- a/src/corelib/thread/qfuturesynchronizer.qdoc
+++ b/src/corelib/thread/qfuturesynchronizer.qdoc
@@ -3,9 +3,9 @@
** 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.
+** This file is part of the documentation of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,25 +14,13 @@
** 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.
-**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp
index f418ac1205..82d439a728 100644
--- a/src/corelib/thread/qsemaphore.cpp
+++ b/src/corelib/thread/qsemaphore.cpp
@@ -501,7 +501,7 @@ bool QSemaphore::tryAcquire(int n, int timeout)
/*!
\class QSemaphoreReleaser
- \brief The QSemaphoreReleaser class provides exception-safe deferral of a QSemaphore::release() call
+ \brief The QSemaphoreReleaser class provides exception-safe deferral of a QSemaphore::release() call.
\since 5.10
\ingroup thread
\inmodule QtCore
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 651f260f0e..d8d8be7a26 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -3917,8 +3917,8 @@ T toIntegral_helper(const char *data, bool *ok, int base)
Returns 0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\note The conversion of the number is performed in the default C locale,
irrespective of the user's locale.
@@ -3943,8 +3943,8 @@ qlonglong QByteArray::toLongLong(bool *ok, int base) const
Returns 0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\note The conversion of the number is performed in the default C locale,
irrespective of the user's locale.
@@ -3968,8 +3968,8 @@ qulonglong QByteArray::toULongLong(bool *ok, int base) const
Returns 0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\snippet code/src_corelib_tools_qbytearray.cpp 36
@@ -3995,8 +3995,8 @@ int QByteArray::toInt(bool *ok, int base) const
Returns 0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\note The conversion of the number is performed in the default C locale,
irrespective of the user's locale.
@@ -4022,8 +4022,8 @@ uint QByteArray::toUInt(bool *ok, int base) const
Returns 0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\snippet code/src_corelib_tools_qbytearray.cpp 37
@@ -4050,8 +4050,8 @@ long QByteArray::toLong(bool *ok, int base) const
Returns 0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\note The conversion of the number is performed in the default C locale,
irrespective of the user's locale.
@@ -4074,8 +4074,8 @@ ulong QByteArray::toULong(bool *ok, int base) const
Returns 0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\note The conversion of the number is performed in the default C locale,
irrespective of the user's locale.
@@ -4099,8 +4099,8 @@ short QByteArray::toShort(bool *ok, int base) const
Returns 0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\note The conversion of the number is performed in the default C locale,
irrespective of the user's locale.
@@ -4119,8 +4119,8 @@ ushort QByteArray::toUShort(bool *ok, int base) const
Returns 0.0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\snippet code/src_corelib_tools_qbytearray.cpp 38
@@ -4146,8 +4146,8 @@ double QByteArray::toDouble(bool *ok) const
Returns 0.0 if the conversion fails.
- If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to
- false; otherwise *\a{ok} is set to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\note The conversion of the number is performed in the default C locale,
irrespective of the user's locale.
diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp
index 06d01f9829..a54afc5a9d 100644
--- a/src/corelib/tools/qbytearraymatcher.cpp
+++ b/src/corelib/tools/qbytearraymatcher.cpp
@@ -334,7 +334,7 @@ int qFindByteArray(
\class QStaticByteArrayMatcher
\since 5.9
\inmodule QtCore
- \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher
+ \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher.
\ingroup tools
\ingroup string-processing
@@ -366,6 +366,11 @@ int qFindByteArray(
Since this class is designed to do all the up-front calculations at compile-time,
it does not offer a setPattern() method.
+ \note Qt detects the necessary C++14 compiler support by way of the feature
+ test recommendations from
+ \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations}
+ {C++ Committee's Standing Document 6}.
+
\sa QByteArrayMatcher, QStringMatcher
*/
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index 9c1e78ee61..e70630eb12 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -1262,8 +1262,8 @@ QString QLocale::scriptToString(QLocale::Script script)
If the conversion fails the function returns 0.
- If \a ok is not 0, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1280,8 +1280,8 @@ short QLocale::toShort(const QString &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not 0, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1298,8 +1298,8 @@ ushort QLocale::toUShort(const QString &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not 0, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1316,8 +1316,8 @@ int QLocale::toInt(const QString &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not 0, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1334,8 +1334,8 @@ uint QLocale::toUInt(const QString &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not 0, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1354,8 +1354,8 @@ qlonglong QLocale::toLongLong(const QString &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not 0, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1371,8 +1371,11 @@ qulonglong QLocale::toULongLong(const QString &s, bool *ok) const
Returns the float represented by the localized string \a s, or 0.0
if the conversion failed.
- If \a ok is not 0, reports failure by setting
- *ok to false and success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
+
+ This function does not fall back to the 'C' locale if the string
+ cannot be interpreted in this locale.
This function ignores leading and trailing whitespace.
@@ -1388,12 +1391,11 @@ float QLocale::toFloat(const QString &s, bool *ok) const
Returns the double represented by the localized string \a s, or
0.0 if the conversion failed.
- If \a ok is not 0, reports failure by setting
- *ok to false and success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
- Unlike QString::toDouble(), this function does not use
- the 'C' locale if the string cannot be interpreted in this
- locale.
+ This function does not fall back to the 'C' locale if the string
+ cannot be interpreted in this locale.
\snippet code/src_corelib_tools_qlocale.cpp 3
@@ -1415,8 +1417,8 @@ double QLocale::toDouble(const QString &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1435,8 +1437,8 @@ short QLocale::toShort(const QStringRef &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1455,8 +1457,8 @@ ushort QLocale::toUShort(const QStringRef &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1475,8 +1477,8 @@ int QLocale::toInt(const QStringRef &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1495,8 +1497,8 @@ uint QLocale::toUInt(const QStringRef &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1517,8 +1519,8 @@ qlonglong QLocale::toLongLong(const QStringRef &s, bool *ok) const
If the conversion fails the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1536,8 +1538,11 @@ qulonglong QLocale::toULongLong(const QStringRef &s, bool *ok) const
Returns the float represented by the localized string \a s, or 0.0
if the conversion failed.
- If \a ok is not null, reports failure by setting
- *ok to false and success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
+
+ This function does not fall back to the 'C' locale if the string
+ cannot be interpreted in this locale.
This function ignores leading and trailing whitespace.
@@ -1555,12 +1560,11 @@ float QLocale::toFloat(const QStringRef &s, bool *ok) const
Returns the double represented by the localized string \a s, or
0.0 if the conversion failed.
- If \a ok is not null, reports failure by setting
- *ok to false and success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
- Unlike QString::toDouble(), this function does not fall back to
- the "C" locale if the string cannot be interpreted in this
- locale.
+ This function does not fall back to the 'C' locale if the string
+ cannot be interpreted in this locale.
\snippet code/src_corelib_tools_qlocale.cpp 3
@@ -1585,8 +1589,8 @@ double QLocale::toDouble(const QStringRef &s, bool *ok) const
If the conversion fails, the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1605,8 +1609,8 @@ short QLocale::toShort(QStringView s, bool *ok) const
If the conversion fails, the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1625,8 +1629,8 @@ ushort QLocale::toUShort(QStringView s, bool *ok) const
If the conversion fails, the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1645,8 +1649,8 @@ int QLocale::toInt(QStringView s, bool *ok) const
If the conversion fails, the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1665,8 +1669,8 @@ uint QLocale::toUInt(QStringView s, bool *ok) const
If the conversion fails, the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1687,8 +1691,8 @@ qlonglong QLocale::toLongLong(QStringView s, bool *ok) const
If the conversion fails, the function returns 0.
- If \a ok is not null, failure is reported by setting *ok to false, and
- success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1706,8 +1710,8 @@ qulonglong QLocale::toULongLong(QStringView s, bool *ok) const
Returns the float represented by the localized string \a s, or 0.0
if the conversion failed.
- If \a ok is not null, reports failure by setting
- *ok to false and success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
This function ignores leading and trailing whitespace.
@@ -1725,8 +1729,8 @@ float QLocale::toFloat(QStringView s, bool *ok) const
Returns the double represented by the localized string \a s, or
0.0 if the conversion failed.
- If \a ok is not null, reports failure by setting
- *ok to false and success by setting *ok to true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
Unlike QString::toDouble(), this function does not fall back to
the "C" locale if the string cannot be interpreted in this
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp
index 22cf516b68..2d5fd2a00e 100644
--- a/src/corelib/tools/qsharedpointer.cpp
+++ b/src/corelib/tools/qsharedpointer.cpp
@@ -46,7 +46,7 @@
/*!
\class QSharedPointer
\inmodule QtCore
- \brief The QSharedPointer class holds a strong reference to a shared pointer
+ \brief The QSharedPointer class holds a strong reference to a shared pointer.
\since 4.5
\reentrant
@@ -315,7 +315,7 @@
/*!
\class QWeakPointer
\inmodule QtCore
- \brief The QWeakPointer class holds a weak reference to a shared pointer
+ \brief The QWeakPointer class holds a weak reference to a shared pointer.
\since 4.5
\reentrant
@@ -373,7 +373,7 @@
/*!
\class QEnableSharedFromThis
\inmodule QtCore
- \brief A base class that allows obtaining a QSharedPointer for an object already managed by a shared pointer
+ \brief A base class that allows obtaining a QSharedPointer for an object already managed by a shared pointer.
\since 5.4
You can inherit this class when you need to create a QSharedPointer
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index b6731cffcd..d3a6851e2c 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -7104,8 +7104,8 @@ QString QString::vasprintf(const char *cformat, va_list ap)
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -7146,8 +7146,8 @@ qlonglong QString::toIntegral_helper(const QChar *data, int len, bool *ok, int b
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -7190,8 +7190,8 @@ qulonglong QString::toIntegral_helper(const QChar *data, uint len, bool *ok, int
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -7221,8 +7221,8 @@ long QString::toLong(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -7251,8 +7251,8 @@ ulong QString::toULong(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -7280,8 +7280,8 @@ int QString::toInt(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -7309,8 +7309,8 @@ uint QString::toUInt(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -7338,8 +7338,8 @@ short QString::toShort(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -7368,8 +7368,8 @@ ushort QString::toUShort(bool *ok, int base) const
Returns 0.0 if the conversion fails.
- If a conversion error occurs, \c{*}\a{ok} is set to \c false;
- otherwise \c{*}\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
\snippet qstring/main.cpp 66
@@ -7404,21 +7404,30 @@ double QString::toDouble(bool *ok) const
/*!
Returns the string converted to a \c float value.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true. Returns 0.0 if the conversion fails.
+ Returns 0.0 if the conversion fails.
- This function ignores leading and trailing whitespace.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
+
+ \warning The QString content may only contain valid numerical characters
+ which includes the plus/minus sign, the characters g and e used in scientific
+ notation, and the decimal point. Including the unit or additional characters
+ leads to a conversion error.
The string conversion will always happen in the 'C' locale. For locale
dependent conversion use QLocale::toFloat()
+ For historical reasons, this function does not handle
+ thousands group separators. If you need to convert such numbers,
+ use QLocale::toFloat().
+
Example:
\snippet qstring/main.cpp 71
This function ignores leading and trailing whitespace.
- \sa number(), toDouble(), toInt(), QLocale::toFloat()
+ \sa number(), toDouble(), toInt(), QLocale::toFloat(), trimmed()
*/
float QString::toFloat(bool *ok) const
@@ -7611,13 +7620,12 @@ QString QString::number(qulonglong n, int base)
QString QString::number(double n, char f, int prec)
{
QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
- uint flags = 0;
+ uint flags = QLocaleData::ZeroPadExponent;
if (qIsUpper(f))
- flags = QLocaleData::CapitalEorX;
- f = qToLower(f);
+ flags |= QLocaleData::CapitalEorX;
- switch (f) {
+ switch (qToLower(f)) {
case 'f':
form = QLocaleData::DFDecimal;
break;
@@ -8676,14 +8684,13 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
unsigned flags = QLocaleData::NoFlags;
if (fillChar == QLatin1Char('0'))
- flags = QLocaleData::ZeroPadded;
+ flags |= QLocaleData::ZeroPadded;
if (qIsUpper(fmt))
flags |= QLocaleData::CapitalEorX;
- fmt = qToLower(fmt);
QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
- switch (fmt) {
+ switch (qToLower(fmt)) {
case 'f':
form = QLocaleData::DFDecimal;
break;
@@ -8702,7 +8709,7 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
QString arg;
if (d.occurrences > d.locale_occurrences)
- arg = QLocaleData::c()->doubleToString(a, prec, form, fieldWidth, flags);
+ arg = QLocaleData::c()->doubleToString(a, prec, form, fieldWidth, flags | QLocaleData::ZeroPadExponent);
QString locale_arg;
if (d.locale_occurrences > 0) {
@@ -11772,8 +11779,8 @@ QStringRef QStringRef::trimmed() const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -11797,8 +11804,8 @@ qint64 QStringRef::toLongLong(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -11824,8 +11831,8 @@ quint64 QStringRef::toULongLong(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -11851,8 +11858,8 @@ long QStringRef::toLong(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -11877,8 +11884,8 @@ ulong QStringRef::toULong(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -11902,8 +11909,8 @@ int QStringRef::toInt(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -11927,8 +11934,8 @@ uint QStringRef::toUInt(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -11952,8 +11959,8 @@ short QStringRef::toShort(bool *ok, int base) const
base, which is 10 by default and must be between 2 and 36, or 0.
Returns 0 if the conversion fails.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
If \a base is 0, the C language convention is used: If the string
begins with "0x", base 16 is used; if the string begins with "0",
@@ -11978,8 +11985,8 @@ ushort QStringRef::toUShort(bool *ok, int base) const
Returns 0.0 if the conversion fails.
- If a conversion error occurs, \c{*}\a{ok} is set to \c false;
- otherwise \c{*}\a{ok} is set to \c true.
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
The string conversion will always happen in the 'C' locale. For locale
dependent conversion use QLocale::toDouble()
@@ -12001,8 +12008,10 @@ double QStringRef::toDouble(bool *ok) const
/*!
Returns the string converted to a \c float value.
- If a conversion error occurs, *\a{ok} is set to \c false; otherwise
- *\a{ok} is set to \c true. Returns 0.0 if the conversion fails.
+ Returns 0.0 if the conversion fails.
+
+ If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
+ to \c false, and success by setting *\a{ok} to \c true.
The string conversion will always happen in the 'C' locale. For locale
dependent conversion use QLocale::toFloat()
diff --git a/src/corelib/tools/qstringiterator.qdoc b/src/corelib/tools/qstringiterator.qdoc
index caec8803f3..9d7c54ce9f 100644
--- a/src/corelib/tools/qstringiterator.qdoc
+++ b/src/corelib/tools/qstringiterator.qdoc
@@ -3,9 +3,9 @@
** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtCore module of the Qt Toolkit.
+** This file is part of the documentation of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,25 +14,13 @@
** 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.
-**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/corelib/tools/qtimezoneprivate_android.cpp b/src/corelib/tools/qtimezoneprivate_android.cpp
index c3f8c3e0d9..b60093617f 100644
--- a/src/corelib/tools/qtimezoneprivate_android.cpp
+++ b/src/corelib/tools/qtimezoneprivate_android.cpp
@@ -82,7 +82,24 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId)
QJNIObjectPrivate jo_ianaId = QJNIObjectPrivate::fromString( QString::fromUtf8(ianaId) );
androidTimeZone = QJNIObjectPrivate::callStaticObjectMethod( "java.util.TimeZone", "getTimeZone", "(Ljava/lang/String;)Ljava/util/TimeZone;", static_cast<jstring>(jo_ianaId.object()) );
- if (ianaId.isEmpty())
+ // Painfully, JNI gives us back a default zone object if it doesn't
+ // recognize the name; so check for whether ianaId is a recognized name of
+ // the zone object we got and ignore the zone if not.
+ bool found = false;
+ // Try checking ianaId against getID(), getDisplayName():
+ QJNIObjectPrivate jname = androidTimeZone.callObjectMethod("getID", "()Ljava/lang/String;");
+ found = (jname.toString().toUtf8() == ianaId);
+ for (int style = 1; !found && style-- > 0;) {
+ for (int dst = 1; !found && dst-- > 0;) {
+ jname = androidTimeZone.callObjectMethod("getDisplayName", "(ZI;)Ljava/lang/String;",
+ bool(dst), style);
+ found = (jname.toString().toUtf8() == ianaId);
+ }
+ }
+
+ if (!found)
+ m_id.clear();
+ else if (ianaId.isEmpty())
m_id = systemTimeZoneId();
else
m_id = ianaId;
diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc
index 9a08b030f7..75b17a4207 100644
--- a/src/corelib/tools/qvector.qdoc
+++ b/src/corelib/tools/qvector.qdoc
@@ -3,9 +3,9 @@
** 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.
+** This file is part of the documentation of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,25 +14,13 @@
** 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.
-**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp b/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp
index 0f43cd73fb..0fc7a2b26c 100644
--- a/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp
+++ b/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp
@@ -48,218 +48,6 @@
**
****************************************************************************/
-//! [0]
-class MainApplicationAdaptor: public QDBusAbstractAdaptor
-{
- Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication")
- Q_PROPERTY(QString caption READ caption WRITE setCaption)
- Q_PROPERTY(QString organizationName READ organizationName)
- Q_PROPERTY(QString organizationDomain READ organizationDomain)
-
-private:
- QApplication *app;
-
-public:
- MainApplicationAdaptor(QApplication *application)
- : QDBusAbstractAdaptor(application), app(application)
- {
- connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit()));
- connect(application, SIGNAL(focusChanged(QWidget*,QWidget*)),
- SLOT(focusChangedSlot(QWidget*,QWidget*)));
- }
-
- QString caption()
- {
- if (app->hasMainWindow())
- return app->mainWindow()->caption();
- return QString(""); // must not return a null QString
- }
-
- void setCaption(const QString &newCaption)
- {
- if (app->hasMainWindow())
- app->mainWindow()->setCaption(newCaption);
- }
-
- QString organizationName()
- {
- return app->organizationName();
- }
-
- QString organizationDomain()
- {
- return app->organizationDomain();
- }
-
-public slots:
- Q_NOREPLY void quit()
- { app->quit(); }
-
- void reparseConfiguration()
- { app->reparseConfiguration(); }
-
- QString mainWindowObject()
- {
- if (app->hasMainWindow())
- return QString("/%1/mainwindow").arg(app->applicationName());
- return QString();
- }
-
- void setSessionManagement(bool enable)
- {
- if (enable)
- app->enableSessionManagement();
- else
- app->disableSessionManagement();
- }
-
-private slots:
- void focusChangedSlot(QWidget *, QWidget *now)
- {
- if (now == app->mainWindow())
- emit mainWindowHasFocus();
- }
-
-signals:
- void aboutToQuit();
- void mainWindowHasFocus();
-};
-//! [0]
-
-
-//! [1]
-interface org.kde.DBus.MainApplication
-{
- property readwrite STRING caption
- property read STRING organizationName
- property read STRING organizationDomain
-
- method quit() annotation("org.freedesktop.DBus.Method.NoReply", "true")
- method reparseConfiguration()
- method mainWindowObject(out STRING)
- method disableSessionManagement(in BOOLEAN enable)
-
- signal aboutToQuit()
- signal mainWindowHasFocus()
-}
-//! [1]
-
-
-//! [2]
-int main(int argc, char **argv)
-{
- // create the QApplication object
- QApplication app(argc, argv);
-
- // create the MainApplication adaptor:
- new MainApplicationAdaptor(app);
-
- // connect to D-Bus and register as an object:
- QDBusConnection::sessionBus().registerObject("/MainApplication", &app);
-
- // add main window, etc.
- [...]
-
- app.exec();
-}
-//! [2]
-
-
-//! [3]
-class MainApplicationAdaptor: public QDBusAbstractAdaptor
-{
- Q_OBJECT
- Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication")
-//! [3]
-
-
-//! [4]
- Q_PROPERTY(QString caption READ caption WRITE setCaption)
- Q_PROPERTY(QString organizationName READ organizationName)
- Q_PROPERTY(QString organizationDomain READ organizationDomain)
-//! [4]
-
-
-//! [5]
-QString caption()
-{
- if (app->hasMainWindow())
- return app->mainWindow()->caption();
- return QString();
-}
-
-void setCaption(const QString &newCaption)
-{
- if (app->hasMainWindow())
- app->mainWindow()->setCaption(newCaption);
-}
-
-QString organizationName()
-{
- return app->organizationName();
-}
-
-QString organizationDomain()
-{
- return app->organizationDomain();
-}
-//! [5]
-
-
-//! [6]
-MyInterfaceAdaptor(QApplication *application)
- : QDBusAbstractAdaptor(application), app(application)
-{
- connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit());
- connect(application, SIGNAL(focusChanged(QWidget*,QWidget*)),
- SLOT(focusChangedSlot(QWidget*,QWidget*)));
-}
-//! [6]
-
-
-//! [7]
-public slots:
- Q_NOREPLY void quit()
- { app->quit(); }
-
- void reparseConfiguration()
- { app->reparseConfiguration(); }
-
- QString mainWindowObject()
- {
- if (app->hasMainWindow())
- return QString("/%1/mainwindow").arg(app->applicationName());
- return QString();
- }
-
- void setSessionManagement(bool enable)
- {
- if (enable)
- app->enableSessionManagement();
- else
- app->disableSessionManagement();
- }
-//! [7]
-
-
-//! [8]
-signals:
- void aboutToQuit();
- void mainWindowHasFocus();
-//! [8]
-
-
-//! [9]
-private slots:
- void focusChangedSlot(QWidget *, QWidget *now)
- {
- if (now == app->mainWindow())
- emit mainWindowHasFocus();
- }
-//! [9]
-
-
//! [10]
struct RequestData
{
diff --git a/src/dbus/doc/src/dbus-adaptors.qdoc b/src/dbus/doc/src/dbus-adaptors.qdoc
index 0b0dacf819..9ebf0cedf2 100644
--- a/src/dbus/doc/src/dbus-adaptors.qdoc
+++ b/src/dbus/doc/src/dbus-adaptors.qdoc
@@ -68,133 +68,14 @@
\li \l{Declaring Slots in D-Bus Adaptors}
\li \l{Declaring Signals in D-Bus Adaptors}
\li \l{The Qt D-Bus Type System}
- \li \l{D-Bus Adaptor Example}
+ \li In the \l{D-Bus Complex Ping Pong Example}, \c complexpong.h and
+ \c complexpong.cpp show an implementation of QDBusAbstractAdaptor.
\endlist
\sa QDBusAbstractAdaptor
*/
/*!
- \page qdbusadaptorexample.html
- \title D-Bus Adaptor Example
-
- \previouspage The Qt D-Bus Type System
- \contentspage Using Qt D-Bus Adaptors
-
- The following example code shows how a D-Bus interface can be implemented
- using an adaptor.
-
- A sample usage of QDBusAbstractAdaptor is as follows:
- \snippet code/doc_src_qdbusadaptors.cpp 0
-
- The code above would create an interface that could be represented more or less in the following
- canonical representation:
- \snippet code/doc_src_qdbusadaptors.cpp 1
-
- This adaptor could be used in the application's main function as follows
- \snippet code/doc_src_qdbusadaptors.cpp 2
-
- Break-down analysis:
- \tableofcontents
-
- \section1 The Header
-
- The header of the example is:
- \snippet code/doc_src_qdbusadaptors.cpp 3
-
- The code does the following:
- \list
- \li it declares the adaptor MainApplicationAdaptor, which descends from QDBusAbstractAdaptor
- \li it declares the Qt meta-object data using the Q_OBJECT macro
- \li it declares the name of the D-Bus interface it implements.
- \endlist
-
- \section1 The Properties
-
- The properties are declared as follows:
- \snippet code/doc_src_qdbusadaptors.cpp 4
-
- And are implemented as follows:
- \snippet code/doc_src_qdbusadaptors.cpp 5
-
- The code declares three properties: one of them is a read-write property called "caption" of
- string type. The other two are read-only, also of the string type.
-
- The properties organizationName and organizationDomain are simple relays of the app object's
- organizationName and organizationDomain properties. However, the caption property requires
- verifying if the application has a main window associated with it: if there isn't any, the
- caption property is empty. Note how it is possible to access data defined in other objects
- through the getter/setter functions.
-
- \section1 The Constructor
-
- The constructor:
- \snippet code/doc_src_qdbusadaptors.cpp 6
-
- The constructor does the following:
- \list
- \li it initialises its base class (QDBusAbstractAdaptor) with the parent object it is related to.
- \li it stores the app pointer in a member variable. Note that it would be possible to access the
- same object using the QDBusAbstractAdaptor::object() function, but it would be necessary to
- use \a static_cast<> to properly access the methods in QApplication that are not part of
- QObject.
- \li it connects the application's signal \a aboutToQuit to its own signal \a aboutToQuit.
- \li it connects the application's signal \a focusChanged to a private slot to do some further
- processing before emitting a D-Bus signal.
- \endlist
-
- Note that there is no destructor in the example. An eventual destructor could be used to emit
- one last signal before the object is destroyed, for instance.
-
- \section1 Slots/methods
-
- The public slots in the example (which will be exported as D-Bus methods) are the following:
- \snippet code/doc_src_qdbusadaptors.cpp 7
-
- This snippet of code defines 4 methods with different properties each:
- \list 1
- \li \c quit: this method takes no parameters and is defined to be asynchronous. That is, callers
- are expected to use "fire-and-forget" mechanism when calling this method, since it provides no
- useful reply. This is represented in D-Bus by the use of the
- org.freedesktop.DBus.Method.NoReply annotation. See \l Q_NOREPLY for more information on
- asynchronous methods
-
- \li \c reparseConfiguration: this simple method, with no input or output arguments simply relays
- the call to the application's reparseConfiguration member function.
-
- \li \c mainWindowObject: this method takes no input parameter, but returns one string output
- argument, containing the path to the main window object (if the application has a main
- window), or an empty string if it has no main window. Note that this method could have also
- been written: void mainWindowObject(QString &path).
-
- \li \c setSessionManagement: this method takes one input argument (a boolean) and, depending on
- its value, it calls one function or another in the application.
- \endlist
-
- See also: \l Q_NOREPLY.
-
- \section1 Signals
-
- The signals in this example are defined as follows:
- \snippet code/doc_src_qdbusadaptors.cpp 8
-
- However, signal definition isn't enough: signals have to be emitted. One simple way of emitting
- signals is to connect another signal to them, so that Qt's signal handling system chains them
- automatically. This is what is done for the \a aboutToQuit signal.
-
- When this is the case, one can use the QDBusAbstractAdaptor::setAutoRelaySignals to
- automatically connect every signal from the real object to the adaptor.
-
- When simple signal-to-signal connection isn't enough, one can use a private slot do do some
- work. This is what was done for the mainWindowHasFocus signal:
- \snippet code/doc_src_qdbusadaptors.cpp 9
-
- This private slot (which will not be exported as a method via D-Bus) was connected to the
- \c focusChanged signal in the adaptor's constructor. It is therefore able to shape the
- application's signal into what the interface expects it to be.
-*/
-
-/*!
\page qdbusdeclaringslots.html
\title Declaring Slots in D-Bus Adaptors
@@ -230,8 +111,8 @@
synchronize with the caller should provide its own method of synchronization.
Asynchronous slots are marked by the keyword \l Q_NOREPLY in the method
- signature, before the \c void return type and the slot name. (See the
- \c quit() slot in the \l{D-Bus Adaptor Example}).
+ signature, before the \c void return type and the slot name. The \c quit()
+ slot in the \l {D-Bus Complex Ping Pong Example} is an example of this.
\section1 Input-Only Slots
@@ -341,8 +222,8 @@
However, signals must still be emitted. The easiest way to emit an adaptor
signal is to connect another signal to it, so that Qt's signals and slots
mechanism automatically emits the adaptor signal, too. This can be done in
- the adaptor's constructor, as has been done in the
- \l{D-Bus Adaptor Example}{D-Bus Adaptor example}.
+ the adaptor's constructor, as you can see in the \l {D-Bus Complex Ping
+ Pong Example}.
The QDBusAbstractAdaptor::setAutoRelaySignals() convenience function can also
be used to make and break connections between signals in the real object and
@@ -360,7 +241,6 @@
\previouspage Declaring Signals in D-Bus Adaptors
\contentspage Using Qt D-Bus Adaptors
- \nextpage D-Bus Adaptor Example
D-Bus has an extensible type system based on a few primitives and
composition of the primitives in arrays and structures. Qt D-Bus
diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp
index 7ddf68daa0..148bd54147 100644
--- a/src/dbus/qdbusabstractinterface.cpp
+++ b/src/dbus/qdbusabstractinterface.cpp
@@ -305,7 +305,7 @@ int QDBusAbstractInterfaceBase::qt_metacall(QMetaObject::Call _c, int _id, void
\inmodule QtDBus
\since 4.2
- \brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the Qt D-Bus binding, allowing access to remote interfaces
+ \brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the Qt D-Bus binding, allowing access to remote interfaces.
Generated-code classes also derive from QDBusAbstractInterface,
all methods described here are also valid for generated-code
diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp
index bd6eb9eca3..2a31dd950a 100644
--- a/src/dbus/qdbuspendingcall.cpp
+++ b/src/dbus/qdbuspendingcall.cpp
@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
\ingroup shared
\since 4.5
- \brief The QDBusPendingCall class refers to one pending asynchronous call
+ \brief The QDBusPendingCall class refers to one pending asynchronous call.
A QDBusPendingCall object is a reference to a method call that was
sent over D-Bus without waiting for a reply. QDBusPendingCall is an
@@ -91,7 +91,7 @@ QT_BEGIN_NAMESPACE
\since 4.5
\brief The QDBusPendingCallWatcher class provides a convenient way for
- waiting for asynchronous replies
+ waiting for asynchronous replies.
The QDBusPendingCallWatcher provides the finished() signal that will be
emitted when a reply arrives.
diff --git a/src/dbus/qdbuspendingreply.cpp b/src/dbus/qdbuspendingreply.cpp
index c0baa4a005..fef6f36432 100644
--- a/src/dbus/qdbuspendingreply.cpp
+++ b/src/dbus/qdbuspendingreply.cpp
@@ -49,7 +49,7 @@
\inmodule QtDBus
\since 4.5
- \brief The QDBusPendingReply class contains the reply to an asynchronous method call
+ \brief The QDBusPendingReply class contains the reply to an asynchronous method call.
The QDBusPendingReply is a template class with up to 8 template
parameters. Those parameters are the types that will be used to
diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp
index f55e90c153..235bc5bd7d 100644
--- a/src/gui/itemmodels/qstandarditemmodel.cpp
+++ b/src/gui/itemmodels/qstandarditemmodel.cpp
@@ -142,6 +142,8 @@ void QStandardItemPrivate::setChild(int row, int column, QStandardItem *item,
oldItem->d_func()->setModel(0);
delete oldItem;
children.replace(index, item);
+ if (item)
+ item->d_func()->lastKnownIndex = index;
if (model && emitChanged)
emit model->layoutChanged();
@@ -475,6 +477,8 @@ bool QStandardItemPrivate::insertRows(int row, const QList<QStandardItem*> &item
item->d_func()->parent = q;
int index = childIndex(i + row, 0);
children.replace(index, item);
+ if (item)
+ item->d_func()->lastKnownIndex = index;
}
if (model)
model->d_func()->rowsInserted(q, row, count);
@@ -512,6 +516,8 @@ bool QStandardItemPrivate::insertRows(int row, int count, const QList<QStandardI
}
}
children.replace(index, item);
+ if (item)
+ item->d_func()->lastKnownIndex = index;
++index;
}
}
@@ -558,6 +564,8 @@ bool QStandardItemPrivate::insertColumns(int column, int count, const QList<QSta
int c = column + (i % count);
int index = childIndex(r, c);
children.replace(index, item);
+ if (item)
+ item->d_func()->lastKnownIndex = index;
}
}
if (model)
diff --git a/src/gui/itemmodels/qstandarditemmodel_p.h b/src/gui/itemmodels/qstandarditemmodel_p.h
index d3ff2787a5..00e83f7b08 100644
--- a/src/gui/itemmodels/qstandarditemmodel_p.h
+++ b/src/gui/itemmodels/qstandarditemmodel_p.h
@@ -114,7 +114,7 @@ public:
rows(0),
columns(0),
q_ptr(0),
- lastIndexOf(2)
+ lastKnownIndex(-1)
{ }
inline int childIndex(int row, int column) const {
@@ -124,12 +124,40 @@ public:
}
return (row * columnCount()) + column;
}
- inline int childIndex(const QStandardItem *child) {
- int start = qMax(0, lastIndexOf -2);
- lastIndexOf = children.indexOf(const_cast<QStandardItem*>(child), start);
- if (lastIndexOf == -1 && start != 0)
- lastIndexOf = children.lastIndexOf(const_cast<QStandardItem*>(child), start);
- return lastIndexOf;
+ inline int childIndex(const QStandardItem *child) const {
+ const int lastChild = children.size() - 1;
+ int &childsLastIndexInParent = child->d_func()->lastKnownIndex;
+ if (childsLastIndexInParent != -1 && childsLastIndexInParent <= lastChild) {
+ if (children.at(childsLastIndexInParent) == child)
+ return childsLastIndexInParent;
+ } else {
+ childsLastIndexInParent = lastChild / 2;
+ }
+
+ // assuming the item is in the vicinity of the previous index, iterate forwards and
+ // backwards through the children
+ int backwardIter = childsLastIndexInParent - 1;
+ int forwardIter = childsLastIndexInParent;
+ Q_FOREVER {
+ if (forwardIter <= lastChild) {
+ if (children.at(forwardIter) == child) {
+ childsLastIndexInParent = forwardIter;
+ break;
+ }
+ ++forwardIter;
+ } else if (backwardIter < 0) {
+ childsLastIndexInParent = -1;
+ break;
+ }
+ if (backwardIter >= 0) {
+ if (children.at(backwardIter) == child) {
+ childsLastIndexInParent = backwardIter;
+ break;
+ }
+ --backwardIter;
+ }
+ }
+ return childsLastIndexInParent;
}
QPair<int, int> position() const;
void setChild(int row, int column, QStandardItem *item,
@@ -170,7 +198,7 @@ public:
QStandardItem *q_ptr;
- int lastIndexOf;
+ mutable int lastKnownIndex; // this is a cached value
};
class QStandardItemModelPrivate : public QAbstractItemModelPrivate
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 57123f4831..91348265cd 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1300,10 +1300,18 @@ void QGuiApplicationPrivate::createPlatformIntegration()
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
if (!sessionType.isEmpty()) {
- if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb")))
+ if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) {
platformName = QByteArrayLiteral("xcb");
- else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland")))
- platformName = QByteArrayLiteral("wayland");
+ } else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) {
+ QByteArray currentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower();
+ QByteArray sessionDesktop = qgetenv("XDG_SESSION_DESKTOP").toLower();
+ if (currentDesktop.contains("gnome") || sessionDesktop.contains("gnome")) {
+ qInfo() << "Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome."
+ << "Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.";
+ } else {
+ platformName = QByteArrayLiteral("wayland");
+ }
+ }
}
#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
// Add it as fallback in case XDG_SESSION_TYPE is something wrong
diff --git a/src/gui/kernel/qpixelformat.cpp b/src/gui/kernel/qpixelformat.cpp
index c132a1418e..c28fe7ac63 100644
--- a/src/gui/kernel/qpixelformat.cpp
+++ b/src/gui/kernel/qpixelformat.cpp
@@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtGui
\since 5.4
\brief QPixelFormat is a class for describing different pixel
- layouts in graphics buffers
+ layouts in graphics buffers.
In Qt there is a often a need to represent the layout of the pixels in a
graphics buffer. Internally QPixelFormat stores everything in a 64 bit
diff --git a/src/gui/kernel/qrasterwindow.cpp b/src/gui/kernel/qrasterwindow.cpp
index d06fee62cf..c88654e794 100644
--- a/src/gui/kernel/qrasterwindow.cpp
+++ b/src/gui/kernel/qrasterwindow.cpp
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
\class QRasterWindow
\inmodule QtGui
\since 5.4
- \brief QRasterWindow is a convenience class for using QPainter on a QWindow
+ \brief QRasterWindow is a convenience class for using QPainter on a QWindow.
QRasterWindow is a QWindow with a raster-based, non-OpenGL surface. On top of
the functionality offered by QWindow, QRasterWindow adds a virtual
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 2258027979..75f63c046f 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -2840,7 +2840,7 @@ void QWindow::setVulkanInstance(QVulkanInstance *instance)
}
/*!
- \return the associrated Vulkan instance or \c null if there is none.
+ \return the associated Vulkan instance or \c null if there is none.
*/
QVulkanInstance *QWindow::vulkanInstance() const
{
diff --git a/src/gui/opengl/qopenglfunctions_es2.cpp b/src/gui/opengl/qopenglfunctions_es2.cpp
index 59e275dce1..dd2b3af80b 100644
--- a/src/gui/opengl/qopenglfunctions_es2.cpp
+++ b/src/gui/opengl/qopenglfunctions_es2.cpp
@@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtGui
\since 5.1
\wrapper
- \brief The QOpenGLFunctions_ES2 class provides all functions for OpenGL ES 2
+ \brief The QOpenGLFunctions_ES2 class provides all functions for OpenGL ES 2.
This class is a wrapper for OpenGL ES 2 functions. See reference pages on
\l {http://www.khronos.org/opengles/sdk/docs/man/}{khronos.org} for
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index fb7e6fce97..e390183893 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -864,20 +864,18 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
if (data) {
cache = (QOpenGL2PEVectorPathCache *) data->data;
- // Check if scale factor is exceeded for curved paths and generate curves if so...
- if (path.isCurved()) {
- qreal scaleFactor = cache->iscale / inverseScale;
- if (scaleFactor < 0.5 || scaleFactor > 2.0) {
+ // Check if scale factor is exceeded and regenerate if so...
+ qreal scaleFactor = cache->iscale / inverseScale;
+ if (scaleFactor < 0.5 || scaleFactor > 2.0) {
#ifdef QT_OPENGL_CACHE_AS_VBOS
- glDeleteBuffers(1, &cache->vbo);
- cache->vbo = 0;
- Q_ASSERT(cache->ibo == 0);
+ glDeleteBuffers(1, &cache->vbo);
+ cache->vbo = 0;
+ Q_ASSERT(cache->ibo == 0);
#else
- free(cache->vertices);
- Q_ASSERT(cache->indices == 0);
+ free(cache->vertices);
+ Q_ASSERT(cache->indices == 0);
#endif
- updateCache = true;
- }
+ updateCache = true;
}
} else {
cache = new QOpenGL2PEVectorPathCache;
@@ -946,19 +944,17 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
if (data) {
cache = (QOpenGL2PEVectorPathCache *) data->data;
- // Check if scale factor is exceeded for curved paths and generate curves if so...
- if (path.isCurved()) {
- qreal scaleFactor = cache->iscale / inverseScale;
- if (scaleFactor < 0.5 || scaleFactor > 2.0) {
+ // Check if scale factor is exceeded and regenerate if so...
+ qreal scaleFactor = cache->iscale / inverseScale;
+ if (scaleFactor < 0.5 || scaleFactor > 2.0) {
#ifdef QT_OPENGL_CACHE_AS_VBOS
- glDeleteBuffers(1, &cache->vbo);
- glDeleteBuffers(1, &cache->ibo);
+ glDeleteBuffers(1, &cache->vbo);
+ glDeleteBuffers(1, &cache->ibo);
#else
- free(cache->vertices);
- free(cache->indices);
+ free(cache->vertices);
+ free(cache->indices);
#endif
- updateCache = true;
- }
+ updateCache = true;
}
} else {
cache = new QOpenGL2PEVectorPathCache;
diff --git a/src/gui/painting/qmatrix.cpp b/src/gui/painting/qmatrix.cpp
index 681490e347..24b33243da 100644
--- a/src/gui/painting/qmatrix.cpp
+++ b/src/gui/painting/qmatrix.cpp
@@ -992,12 +992,12 @@ bool QMatrix::operator==(const QMatrix &m) const
uint qHash(const QMatrix &key, uint seed) Q_DECL_NOTHROW
{
QtPrivate::QHashCombine hash;
- seed = hash(key.m11(), seed);
- seed = hash(key.m12(), seed);
- seed = hash(key.m21(), seed);
- seed = hash(key.m22(), seed);
- seed = hash(key.dx(), seed);
- seed = hash(key.dy(), seed);
+ seed = hash(seed, key.m11());
+ seed = hash(seed, key.m12());
+ seed = hash(seed, key.m21());
+ seed = hash(seed, key.m22());
+ seed = hash(seed, key.dx());
+ seed = hash(seed, key.dy());
return seed;
}
diff --git a/src/gui/painting/qpagesize.cpp b/src/gui/painting/qpagesize.cpp
index 9cbe6ef911..a1c9f6e417 100644
--- a/src/gui/painting/qpagesize.cpp
+++ b/src/gui/painting/qpagesize.cpp
@@ -908,7 +908,7 @@ QSize QPageSizePrivate::sizePixels(int resolution) const
\class QPageSize
\inmodule QtGui
\since 5.3
- \brief The QPageSize class describes the size and name of a defined page size
+ \brief The QPageSize class describes the size and name of a defined page size.
This class implements support for the set of standard page sizes as defined
in the Adobe Postscript PPD Standard v4.3. It defines the standard set of
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index 09c23fdfa1..cc8d850689 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -344,7 +344,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
QWindowPrivate::get(window)->lastComposeTime.start();
QOpenGLFunctions *funcs = d_ptr->context->functions();
- funcs->glViewport(0, 0, window->width() * window->devicePixelRatio(), window->height() * window->devicePixelRatio());
+ funcs->glViewport(0, 0, qRound(window->width() * window->devicePixelRatio()), qRound(window->height() * window->devicePixelRatio()));
funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1);
funcs->glClear(GL_COLOR_BUFFER_BIT);
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index c5e296b293..040d33fc2a 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -798,15 +798,15 @@ bool QTransform::operator==(const QTransform &o) const
uint qHash(const QTransform &key, uint seed) Q_DECL_NOTHROW
{
QtPrivate::QHashCombine hash;
- seed = hash(key.m11(), seed);
- seed = hash(key.m12(), seed);
- seed = hash(key.m21(), seed);
- seed = hash(key.m22(), seed);
- seed = hash(key.dx(), seed);
- seed = hash(key.dy(), seed);
- seed = hash(key.m13(), seed);
- seed = hash(key.m23(), seed);
- seed = hash(key.m33(), seed);
+ seed = hash(seed, key.m11());
+ seed = hash(seed, key.m12());
+ seed = hash(seed, key.m21());
+ seed = hash(seed, key.m22());
+ seed = hash(seed, key.dx());
+ seed = hash(seed, key.dy());
+ seed = hash(seed, key.m13());
+ seed = hash(seed, key.m23());
+ seed = hash(seed, key.m33());
return seed;
}
diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp
index d89805d18e..a911014a19 100644
--- a/src/gui/text/qplatformfontdatabase.cpp
+++ b/src/gui/text/qplatformfontdatabase.cpp
@@ -264,7 +264,7 @@ bool QSupportedWritingSystems::supported(QFontDatabase::WritingSystem writingSys
/*!
\class QSupportedWritingSystems
\brief The QSupportedWritingSystems class is used when registering fonts with the internal Qt
- fontdatabase
+ fontdatabase.
\ingroup painting
\inmodule QtGui
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index 1d6a04a424..a129beda15 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -84,8 +84,7 @@ qtConfig(http) {
access/qhttpnetworkrequest.cpp \
access/qhttpprotocolhandler.cpp \
access/qhttpthreaddelegate.cpp \
- access/qnetworkreplyhttpimpl.cpp \
- access/qspdyprotocolhandler.cpp
+ access/qnetworkreplyhttpimpl.cpp
HEADERS += \
access/qabstractprotocolhandler_p.h \
@@ -99,6 +98,12 @@ qtConfig(http) {
access/qhttpnetworkrequest_p.h \
access/qhttpprotocolhandler_p.h \
access/qhttpthreaddelegate_p.h \
- access/qnetworkreplyhttpimpl_p.h \
- access/qspdyprotocolhandler_p.h
+ access/qnetworkreplyhttpimpl_p.h
+
+ qtConfig(ssl) {
+ SOURCES += \
+ access/qspdyprotocolhandler.cpp
+ HEADERS += \
+ access/qspdyprotocolhandler_p.h
+ }
}
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 35e79a69f2..76850837d0 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -166,7 +166,7 @@ static void ensureInitialized()
/*!
\class QNetworkAccessManager
\brief The QNetworkAccessManager class allows the application to
- send network requests and receive replies
+ send network requests and receive replies.
\since 4.4
\ingroup network
diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp
index 2ec4acf26c..072a7f249d 100644
--- a/src/network/access/qnetworkcookiejar.cpp
+++ b/src/network/access/qnetworkcookiejar.cpp
@@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
\since 4.4
\inmodule QtNetwork
- \brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects
+ \brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects.
Cookies are small bits of information that stateless protocols
like HTTP use to maintain some persistent information across
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index 11d8f0e3f7..aca9cb1c08 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -61,7 +61,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
\class QNetworkReply
\since 4.4
\brief The QNetworkReply class contains the data and headers for a request
- sent with QNetworkAccessManager
+ sent with QNetworkAccessManager.
\reentrant
\ingroup network
diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc
index 7a95195da2..517e0a72cb 100644
--- a/src/network/doc/src/qtnetwork.qdoc
+++ b/src/network/doc/src/qtnetwork.qdoc
@@ -96,7 +96,7 @@
\title Qt Network C++ Classes
\ingroup modules
\qtvariable network
- \brief Provides classes to make network programming easier and portable
+ \brief Provides classes to make network programming easier and portable.
To include the definitions of the module's classes, use the
following directive:
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
index 11ea40dbce..34db5b4b31 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -1454,8 +1454,8 @@ static bool q_NTLM_SSPI_library_load()
securityDLLHandle = LoadLibrary(L"secur32.dll");
if (securityDLLHandle != NULL) {
INIT_SECURITY_INTERFACE pInitSecurityInterface =
- (INIT_SECURITY_INTERFACE)GetProcAddress(securityDLLHandle,
- "InitSecurityInterfaceW");
+ reinterpret_cast<INIT_SECURITY_INTERFACE>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(securityDLLHandle, "InitSecurityInterfaceW")));
if (pInitSecurityInterface != NULL)
pSecurityFunctionTable = pInitSecurityInterface();
}
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index c303f01648..1b84b26d83 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -1232,6 +1232,8 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL
// it is ok the buffer was to small if bytesRead is larger than
// maxLength then assume bytes read is really maxLenth
ret = qint64(bytesRead) > maxLength ? maxLength : qint64(bytesRead);
+ if (options & QNativeSocketEngine::WantDatagramSender)
+ qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress);
} else {
WS_ERROR_DEBUG(err);
switch (err) {
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index e03b89f58e..71c4f7090c 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -59,7 +59,7 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
/*!
\class QSslConfiguration
- \brief The QSslConfiguration class holds the configuration and state of an SSL connection
+ \brief The QSslConfiguration class holds the configuration and state of an SSL connection.
\since 4.4
\reentrant
diff --git a/src/network/ssl/qsslsocket_openssl11.cpp b/src/network/ssl/qsslsocket_openssl11.cpp
index 96626b6a0f..d028f5fc00 100644
--- a/src/network/ssl/qsslsocket_openssl11.cpp
+++ b/src/network/ssl/qsslsocket_openssl11.cpp
@@ -125,9 +125,12 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
#if defined(Q_OS_WIN)
HINSTANCE hLib = LoadLibraryW(L"Crypt32");
if (hLib) {
- ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW");
- ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore");
- ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore");
+ ptrCertOpenSystemStoreW = reinterpret_cast<PtrCertOpenSystemStoreW>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertOpenSystemStoreW")));
+ ptrCertFindCertificateInStore = reinterpret_cast<PtrCertFindCertificateInStore>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertFindCertificateInStore")));
+ ptrCertCloseStore = reinterpret_cast<PtrCertCloseStore>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertCloseStore")));
if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore)
qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen
} else {
diff --git a/src/network/ssl/qsslsocket_opensslpre11.cpp b/src/network/ssl/qsslsocket_opensslpre11.cpp
index 5782df65cc..062e03f4e6 100644
--- a/src/network/ssl/qsslsocket_opensslpre11.cpp
+++ b/src/network/ssl/qsslsocket_opensslpre11.cpp
@@ -254,9 +254,12 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
#if defined(Q_OS_WIN)
HINSTANCE hLib = LoadLibraryW(L"Crypt32");
if (hLib) {
- ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW");
- ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore");
- ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore");
+ ptrCertOpenSystemStoreW = reinterpret_cast<PtrCertOpenSystemStoreW>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertOpenSystemStoreW")));
+ ptrCertFindCertificateInStore = reinterpret_cast<PtrCertFindCertificateInStore>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertFindCertificateInStore")));
+ ptrCertCloseStore = reinterpret_cast<PtrCertCloseStore>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(hLib, "CertCloseStore")));
if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore)
qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen
} else {
diff --git a/src/platformheaders/nativecontexts/qeglnativecontext.qdoc b/src/platformheaders/nativecontexts/qeglnativecontext.qdoc
index 22e763ec24..3779ea10c8 100644
--- a/src/platformheaders/nativecontexts/qeglnativecontext.qdoc
+++ b/src/platformheaders/nativecontexts/qeglnativecontext.qdoc
@@ -30,7 +30,7 @@
\inmodule QtPlatformHeaders
\since 5.4
- \brief A class encapsulating an EGL context and display handle
+ \brief A class encapsulating an EGL context and display handle.
\note There is no binary compatibility guarantee for this class, meaning
that an application using it is only guaranteed to work with the Qt version it was
diff --git a/src/platformheaders/nativecontexts/qwglnativecontext.qdoc b/src/platformheaders/nativecontexts/qwglnativecontext.qdoc
index ccc5e2b1d0..20563c3906 100644
--- a/src/platformheaders/nativecontexts/qwglnativecontext.qdoc
+++ b/src/platformheaders/nativecontexts/qwglnativecontext.qdoc
@@ -30,7 +30,7 @@
\inmodule QtPlatformHeaders
\since 5.4
- \brief A class encapsulating a WGL context on Windows with desktop OpenGL (opengl32.dll)
+ \brief A class encapsulating a WGL context on Windows with desktop OpenGL (opengl32.dll).
\note There is no binary compatibility guarantee for this class,
meaning that an application using it is only guaranteed to work with the Qt
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
index aab1ab9889..8df8da1a38 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
@@ -1000,7 +1000,7 @@ static QChar *createFontFile(const QString &faceName)
if (!faceName.isEmpty()) {
const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1);
faceNamePtr = new QChar[nameLength + 1];
- memcpy(faceNamePtr, faceName.utf16(), sizeof(wchar_t) * nameLength);
+ memcpy(static_cast<void *>(faceNamePtr), faceName.utf16(), sizeof(wchar_t) * nameLength);
faceNamePtr[nameLength] = 0;
}
return faceNamePtr;
diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
index 04372ae4d9..86a4cd0076 100644
--- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
+++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
@@ -245,18 +245,12 @@ void QEvdevMouseHandler::readMouseData()
m_y += data->value;
posChanged = true;
} else if (data->code == ABS_WHEEL) { // vertical scroll
- // data->value: 1 == up, -1 == down
- if (data->value == 1)
- delta.setY(120);
- else
- delta.setY(-120);
+ // data->value: positive == up, negative == down
+ delta.setY(120 * data->value);
emit handleWheelEvent(delta);
} else if (data->code == ABS_THROTTLE) { // horizontal scroll
- // data->value: 1 == right, -1 == left
- if (data->value == 1)
- delta.setX(-120);
- else
- delta.setX(120);
+ // data->value: positive == right, negative == left
+ delta.setX(-120 * data->value);
emit handleWheelEvent(delta);
}
} else if (data->type == EV_KEY && data->code == BTN_TOUCH) {
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
index 7b7649bc5c..f3cc160b3e 100644
--- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
@@ -368,7 +368,7 @@ QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler()
bool QEvdevTouchScreenHandler::isFiltered() const
{
- return d->m_filtered;
+ return d && d->m_filtered;
}
QTouchDevice *QEvdevTouchScreenHandler::touchDevice() const
diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro
index 7dbb6f6cae..6d4f1b93bd 100644
--- a/src/platformsupport/platformsupport.pro
+++ b/src/platformsupport/platformsupport.pro
@@ -16,7 +16,7 @@ qtConfig(evdev)|qtConfig(tslib)|qtConfig(libinput)|qtConfig(integrityhid) {
input.depends += devicediscovery
}
-if(unix:!darwin)|qtConfig(xcb): \
+if(unix:!uikit)|qtConfig(xcb): \
SUBDIRS += services
qtConfig(opengl): \
diff --git a/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp b/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp
index 2153924ec8..e81d272d4f 100644
--- a/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp
+++ b/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp
@@ -90,12 +90,17 @@ static QString iconTempPath()
static const QString KDEItemFormat = QStringLiteral("org.kde.StatusNotifierItem-%1-%2");
static const QString KDEWatcherService = QStringLiteral("org.kde.StatusNotifierWatcher");
-static const QString TempFileTemplate = iconTempPath() + QLatin1String("/qt-trayicon-XXXXXX.png");
static const QString XdgNotificationService = QStringLiteral("org.freedesktop.Notifications");
static const QString XdgNotificationPath = QStringLiteral("/org/freedesktop/Notifications");
static const QString DefaultAction = QStringLiteral("default");
static int instanceCount = 0;
+static inline QString tempFileTemplate()
+{
+ static const QString TempFileTemplate = iconTempPath() + QLatin1String("/qt-trayicon-XXXXXX.png");
+ return TempFileTemplate;
+}
+
/*!
\class QDBusTrayIcon
\internal
@@ -206,7 +211,7 @@ QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon)
if (!necessary)
return nullptr;
qreal dpr = qGuiApp->devicePixelRatio();
- QTemporaryFile *ret = new QTemporaryFile(TempFileTemplate, this);
+ QTemporaryFile *ret = new QTemporaryFile(tempFileTemplate(), this);
ret->open();
icon.pixmap(QSize(22 * dpr, 22 * dpr)).save(ret);
ret->close();
diff --git a/src/platformsupport/themes/themes.pro b/src/platformsupport/themes/themes.pro
index 44f94fafc8..668a843473 100644
--- a/src/platformsupport/themes/themes.pro
+++ b/src/platformsupport/themes/themes.pro
@@ -6,7 +6,7 @@ CONFIG += static internal_module
DEFINES += QT_NO_CAST_FROM_ASCII
-if(unix:!darwin)|qtConfig(xcb): \
+if(unix:!uikit)|qtConfig(xcb): \
include($$PWD/genericunix/genericunix.pri)
HEADERS += \
diff --git a/src/plugins/imageformats/ico/ico.json b/src/plugins/imageformats/ico/ico.json
index 14093ee471..304e2f1c02 100644
--- a/src/plugins/imageformats/ico/ico.json
+++ b/src/plugins/imageformats/ico/ico.json
@@ -1,4 +1,4 @@
{
"Keys": [ "ico", "cur" ],
- "MimeTypes": [ "image/vnd.microsoft.icon" ]
+ "MimeTypes": [ "image/vnd.microsoft.icon", "image/vnd.microsoft.icon" ]
}
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 2493181bc5..348a9b0c24 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -117,6 +117,9 @@ static void updateFormatFromContext(QSurfaceFormat *format)
format->setProfile(QSurfaceFormat::CompatibilityProfile);
}
+ // NSOpenGLContext is not re-entrant (https://openradar.appspot.com/37064579)
+static QMutex s_contextMutex;
+
QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
const QVariant &nativeHandle)
: m_context(nil),
@@ -248,6 +251,7 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
QWindow *window = static_cast<QCocoaWindow *>(surface)->window();
setActiveWindow(window);
+ QMutexLocker locker(&s_contextMutex);
[m_context flushBuffer];
}
@@ -400,6 +404,7 @@ QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName)
void QCocoaGLContext::update()
{
+ QMutexLocker locker(&s_contextMutex);
[m_context update];
}
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 022242130b..9e168835f1 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -503,7 +503,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
{
const Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
const bool frameless = (flags & Qt::FramelessWindowHint) || windowIsPopupType(type);
- const bool resizeable = !(flags & Qt::CustomizeWindowHint); // Remove zoom button by disabling resize
+
+ // Remove zoom button by disabling resize for CustomizeWindowHint windows, except for
+ // Qt::Tool windows (e.g. dock windows) which should always be resizeable.
+ const bool resizeable = !(flags & Qt::CustomizeWindowHint) || (type == Qt::Tool);
// Select base window type. Note that the value of NSBorderlessWindowMask is 0.
NSUInteger styleMask = (frameless || !resizeable) ? NSBorderlessWindowMask : NSResizableWindowMask;
@@ -517,6 +520,8 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
styleMask |= NSClosableWindowMask;
if (flags & Qt::WindowMinimizeButtonHint)
styleMask |= NSMiniaturizableWindowMask;
+ if (flags & Qt::WindowMaximizeButtonHint)
+ styleMask |= NSResizableWindowMask;
} else {
styleMask |= NSClosableWindowMask | NSTitledWindowMask;
diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm
index 01df0e9337..e61329f169 100644
--- a/src/plugins/platforms/cocoa/qnsview_dragging.mm
+++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm
@@ -165,7 +165,11 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
[nativeCursor set];
// Make sure the cursor is updated correctly if the mouse does not move and window is under cursor
- // by creating a fake move event
+ // by creating a fake move event, unless on 10.14 and later where doing so will trigger a security
+ // warning dialog. FIXME: Find a way to update the cursor without fake mouse events.
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
+ return;
+
if (m_updatingDrag)
return;
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 6079a35d05..1c21879a89 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -72,25 +72,38 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*"));
/*!
Overridden to ensure that the zoomed state always results in a maximized
window, which would otherwise not be the case for borderless windows.
+
+ We also keep the window on the same screen as before; something AppKit
+ sometimes fails to do using its built in logic.
*/
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)proposedFrame
{
Q_UNUSED(proposedFrame);
Q_ASSERT(window == m_cocoaWindow->nativeWindow());
-
- // We compute the maximized state based on the maximum size, and
- // the current position of the window. This may result in the window
- // geometry falling outside of the current screen's available geometry,
- // e.g. when there is not maximize size set, but this is okey, AppKit
- // will then shift and possibly clip the geometry for us.
const QWindow *w = m_cocoaWindow->window();
- QRect maximizedRect = QRect(w->framePosition(), w->maximumSize());
- // QWindow::maximumSize() refers to the client size,
- // but AppKit expects the full frame size.
- maximizedRect.adjust(0, 0, 0, w->frameMargins().top());
+ // maximumSize() refers to the client size, but AppKit expects the full frame size
+ QSizeF maximumSize = w->maximumSize() + QSize(0, w->frameMargins().top());
+
+ // The window should never be larger than the current screen geometry
+ const QRectF screenGeometry = m_cocoaWindow->screen()->geometry();
+ maximumSize = maximumSize.boundedTo(screenGeometry.size());
+
+ // Use the current frame position for the initial maximized frame,
+ // so that the window stays put and just expand, in case its maximum
+ // size is within the screen bounds.
+ QRectF maximizedFrame = QRectF(w->framePosition(), maximumSize);
+
+ // But constrain the frame to the screen bounds in case the frame
+ // extends beyond the screen bounds as a result of starting out
+ // with the current frame position.
+ maximizedFrame.translate(QPoint(
+ qMax(screenGeometry.left() - maximizedFrame.left(), 0.0) +
+ qMin(screenGeometry.right() - maximizedFrame.right(), 0.0),
+ qMax(screenGeometry.top() - maximizedFrame.top(), 0.0) +
+ qMin(screenGeometry.bottom() - maximizedFrame.bottom(), 0.0)));
- return QCocoaScreen::mapToNative(maximizedRect);
+ return QCocoaScreen::mapToNative(maximizedFrame);
}
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro
index 6eb9f2c534..71257d09f7 100644
--- a/src/plugins/platforms/ios/kernel.pro
+++ b/src/plugins/platforms/ios/kernel.pro
@@ -5,8 +5,6 @@ TARGET = qios
# application's main() when the plugin is a shared library.
qtConfig(shared): CONFIG += static
-CONFIG += no_app_extension_api_only
-
QT += \
core-private gui-private \
clipboard_support-private fontdatabase_support-private graphics_support-private
diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm
index cc76d198f5..bf4e9cc900 100644
--- a/src/plugins/platforms/ios/qiosapplicationstate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationstate.mm
@@ -86,7 +86,7 @@ static void qRegisterApplicationStateNotifications()
QLatin1String("Extension loaded, assuming state is active"));
} else {
// Initialize correct startup state, which may not be the Qt default (inactive)
- UIApplicationState startupState = [UIApplication sharedApplication].applicationState;
+ UIApplicationState startupState = qt_apple_sharedApplication().applicationState;
QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application loaded"));
}
}
@@ -95,7 +95,7 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterApplicationStateNotifications)
QIOSApplicationState::QIOSApplicationState()
{
if (!qt_apple_isApplicationExtension()) {
- UIApplicationState startupState = [UIApplication sharedApplication].applicationState;
+ UIApplicationState startupState = qt_apple_sharedApplication().applicationState;
QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application launched"));
}
}
diff --git a/src/plugins/platforms/ios/qiosfiledialog.mm b/src/plugins/platforms/ios/qiosfiledialog.mm
index 5987bc1540..e8a3f5b30e 100644
--- a/src/plugins/platforms/ios/qiosfiledialog.mm
+++ b/src/plugins/platforms/ios/qiosfiledialog.mm
@@ -43,6 +43,8 @@
#include <QtGui/qwindow.h>
#include <QDebug>
+#include <QtCore/private/qcore_mac_p.h>
+
#include "qiosfiledialog.h"
#include "qiosintegration.h"
#include "qiosoptionalplugininterface.h"
@@ -94,7 +96,7 @@ bool QIOSFileDialog::showImagePickerDialog(QWindow *parent)
}
UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window
- : [UIApplication sharedApplication].keyWindow;
+ : qt_apple_sharedApplication().keyWindow;
[window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
return true;
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
index f27b2242df..a523d1be45 100644
--- a/src/plugins/platforms/ios/qiosglobal.mm
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -42,6 +42,8 @@
#include "qiosviewcontroller.h"
#include "qiosscreen.h"
+#include <QtCore/private/qcore_mac_p.h>
+
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application");
@@ -50,13 +52,16 @@ Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
bool isQtApplication()
{
+ if (qt_apple_isApplicationExtension())
+ return false;
+
// Returns \c true if the plugin is in full control of the whole application. This means
// that we control the application delegate and the top view controller, and can take
// actions that impacts all parts of the application. The opposite means that we are
// embedded inside a native iOS application, and should be more focused on playing along
// with native UIControls, and less inclined to change structures that lies outside the
// scope of our QWindows/UIViews.
- static bool isQt = ([[UIApplication sharedApplication].delegate isKindOfClass:[QIOSApplicationDelegate class]]);
+ static bool isQt = ([qt_apple_sharedApplication().delegate isKindOfClass:[QIOSApplicationDelegate class]]);
return isQt;
}
@@ -152,8 +157,13 @@ QT_END_NAMESPACE
+ (id)currentFirstResponder
{
+ if (qt_apple_isApplicationExtension()) {
+ qWarning() << "can't get first responder in application extensions!";
+ return nil;
+ }
+
QtFirstResponderEvent *event = [[[QtFirstResponderEvent alloc] init] autorelease];
- [[UIApplication sharedApplication] sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event];
+ [qt_apple_sharedApplication() sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event];
return event.firstResponder;
}
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 3e22634071..d2229df133 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -49,6 +49,8 @@
#include "qioswindow.h"
#include "quiview.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QGuiApplication>
#include <QtGui/private/qwindow_p.h>
@@ -535,6 +537,11 @@ void QIOSInputContext::scroll(int y)
if (!rootView)
return;
+ if (qt_apple_isApplicationExtension()) {
+ qWarning() << "can't scroll root view in application extension";
+ return;
+ }
+
CATransform3D translationTransform = CATransform3DMakeTranslation(0.0, -y, 0.0);
if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform))
return;
@@ -573,7 +580,7 @@ void QIOSInputContext::scroll(int y)
// Raise all known windows to above the status-bar if we're scrolling the screen,
// while keeping the relative window level between the windows the same.
- NSArray<UIWindow *> *applicationWindows = [[UIApplication sharedApplication] windows];
+ NSArray<UIWindow *> *applicationWindows = [qt_apple_sharedApplication() windows];
static QHash<UIWindow *, UIWindowLevel> originalWindowLevels;
for (UIWindow *window in applicationWindows) {
if (keyboardScrollIsActive && !originalWindowLevels.contains(window))
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index eae0530fbe..9a5a0ab499 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -86,7 +86,7 @@ QIOSIntegration::QIOSIntegration()
, m_accessibility(0)
, m_optionalPlugins(new QFactoryLoader(QIosOptionalPluginInterface_iid, QLatin1String("/platforms/darwin")))
{
- if (Q_UNLIKELY(![UIApplication sharedApplication])) {
+ if (Q_UNLIKELY(!qt_apple_isApplicationExtension() && !qt_apple_sharedApplication())) {
qFatal("Error: You are creating QApplication before calling UIApplicationMain.\n" \
"If you are writing a native iOS application, and only want to use Qt for\n" \
"parts of the application, a good place to create QApplication is from within\n" \
diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm
index 9d05b792c2..a7de9b473a 100644
--- a/src/plugins/platforms/ios/qiosmessagedialog.mm
+++ b/src/plugins/platforms/ios/qiosmessagedialog.mm
@@ -43,6 +43,8 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformtheme.h>
+#include <QtCore/private/qcore_mac_p.h>
+
#include "qiosglobal.h"
#include "quiview.h"
#include "qiosmessagedialog.h"
@@ -126,7 +128,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
[m_alertController addAction:createAction(NoButton)];
}
- UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window : [UIApplication sharedApplication].keyWindow;
+ UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window : qt_apple_sharedApplication().keyWindow;
[window.rootViewController presentViewController:m_alertController animated:YES completion:nil];
return true;
}
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index 96679eaccd..f1121a102b 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -46,6 +46,8 @@
#include "qiosviewcontroller.h"
#include "quiview.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtGui/private/qwindow_p.h>
#include <private/qcoregraphics_p.h>
@@ -269,17 +271,19 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
m_physicalDpi = 96;
}
- for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) {
- if (existingWindow.screen == m_uiScreen) {
- m_uiWindow = [m_uiWindow retain];
- break;
+ if (!qt_apple_isApplicationExtension()) {
+ for (UIWindow *existingWindow in qt_apple_sharedApplication().windows) {
+ if (existingWindow.screen == m_uiScreen) {
+ m_uiWindow = [m_uiWindow retain];
+ break;
+ }
}
- }
- if (!m_uiWindow) {
- // Create a window and associated view-controller that we can use
- m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]];
- m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease];
+ if (!m_uiWindow) {
+ // Create a window and associated view-controller that we can use
+ m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]];
+ m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease];
+ }
}
updateProperties();
@@ -325,17 +329,20 @@ void QIOSScreen::updateProperties()
#ifndef Q_OS_TVOS
if (m_uiScreen == [UIScreen mainScreen]) {
- Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation));
-
QIOSViewController *qtViewController = [m_uiWindow.rootViewController isKindOfClass:[QIOSViewController class]] ?
static_cast<QIOSViewController *>(m_uiWindow.rootViewController) : nil;
if (qtViewController.lockedOrientation) {
+ Q_ASSERT(!qt_apple_isApplicationExtension());
+
// Setting the statusbar orientation (content orientation) on will affect the screen geometry,
// which is not what we want. We want to reflect the screen geometry based on the locked orientation,
// and adjust the available geometry based on the repositioned status bar for the current status
// bar orientation.
+ Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(
+ UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation));
+
Qt::ScreenOrientation lockedOrientation = toQtScreenOrientation(UIDeviceOrientation(qtViewController.lockedOrientation));
QTransform transform = transformBetween(lockedOrientation, statusBarOrientation, m_geometry).inverted();
@@ -489,8 +496,8 @@ Qt::ScreenOrientation QIOSScreen::orientation() const
// the orientation the application was started up in (which may not match
// the physical orientation of the device, but typically does unless the
// application has been locked to a subset of the available orientations).
- if (deviceOrientation == UIDeviceOrientationUnknown)
- deviceOrientation = UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation);
+ if (deviceOrientation == UIDeviceOrientationUnknown && !qt_apple_isApplicationExtension())
+ deviceOrientation = UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation);
// If the device reports face up or face down orientations, we can't map
// them to Qt orientations, so we pretend we're in the same orientation
diff --git a/src/plugins/platforms/ios/qiosservices.mm b/src/plugins/platforms/ios/qiosservices.mm
index 3c44e1d7d6..7222bf6793 100644
--- a/src/plugins/platforms/ios/qiosservices.mm
+++ b/src/plugins/platforms/ios/qiosservices.mm
@@ -40,6 +40,9 @@
#include "qiosservices.h"
#include <QtCore/qurl.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtGui/qdesktopservices.h>
#import <UIKit/UIApplication.h>
@@ -48,6 +51,11 @@ QT_BEGIN_NAMESPACE
bool QIOSServices::openUrl(const QUrl &url)
{
+ if (qt_apple_isApplicationExtension()) {
+ qWarning() << "openUrl not implement for application extensions yet";
+ return false;
+ }
+
if (url == m_handlingUrl)
return false;
@@ -55,12 +63,25 @@ bool QIOSServices::openUrl(const QUrl &url)
return openDocument(url);
NSURL *nsUrl = url.toNSURL();
- UIApplication *application = [UIApplication sharedApplication];
+ UIApplication *application = qt_apple_sharedApplication();
if (![application canOpenURL:nsUrl])
return false;
- [application openURL:nsUrl options:@{} completionHandler:nil];
+ static SEL openUrlSelector = @selector(openURL:options:completionHandler:);
+ NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
+ [UIApplication instanceMethodSignatureForSelector:openUrlSelector]];
+ invocation.target = application;
+ invocation.selector = openUrlSelector;
+
+ static auto kEmptyDictionary = @{};
+ // Indices 0 and 1 are self and _cmd
+ [invocation setArgument:&nsUrl atIndex:2];
+ [invocation setArgument:&kEmptyDictionary atIndex:3];
+ // Fourth argument is nil, so left unset
+
+ [invocation invoke];
+
return true;
}
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index ff696f5b7f..e5419b1766 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -46,6 +46,7 @@
#include <QtGui/private/qinputmethod_p.h>
#include <QtCore/private/qobject_p.h>
+#include <QtCore/private/qcore_mac_p.h>
#include "qiosglobal.h"
#include "qiostextinputoverlay.h"
@@ -462,7 +463,7 @@ static void executeBlockWithoutAnimation(Block block)
if (enabled) {
_focusView = [reinterpret_cast<UIView *>(qApp->focusWindow()->winId()) retain];
- _desktopView = [[UIApplication sharedApplication].keyWindow.rootViewController.view retain];
+ _desktopView = [qt_apple_sharedApplication().keyWindow.rootViewController.view retain];
Q_ASSERT(_focusView && _desktopView && _desktopView.superview);
[_desktopView addGestureRecognizer:self];
} else {
@@ -978,6 +979,11 @@ QIOSTextInputOverlay::QIOSTextInputOverlay()
, m_selectionRecognizer(nullptr)
, m_openMenuOnTapRecognizer(nullptr)
{
+ if (qt_apple_isApplicationExtension()) {
+ qWarning() << "text input overlays disabled in application extensions";
+ return;
+ }
+
connect(qApp, &QGuiApplication::focusObjectChanged, this, &QIOSTextInputOverlay::updateFocusObject);
}
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
index 91980d3f35..5534264a60 100644
--- a/src/plugins/platforms/ios/qiostheme.mm
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -41,6 +41,7 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
+#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/QFont>
@@ -103,7 +104,7 @@ bool QIOSTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const
switch (type) {
case FileDialog:
case MessageDialog:
- return true;
+ return !qt_apple_isApplicationExtension();
default:
return false;
}
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index f254a8692d..ce2aa96ca5 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -41,6 +41,7 @@
#import "qiosviewcontroller.h"
#include <QtCore/qscopedvaluerollback.h>
+#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
@@ -305,15 +306,17 @@
{
[super viewDidLoad];
+ Q_ASSERT(!qt_apple_isApplicationExtension());
+
#ifndef Q_OS_TVOS
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(willChangeStatusBarFrame:)
name:UIApplicationWillChangeStatusBarFrameNotification
- object:[UIApplication sharedApplication]];
+ object:qt_apple_sharedApplication()];
[center addObserver:self selector:@selector(didChangeStatusBarOrientation:)
name:UIApplicationDidChangeStatusBarOrientationNotification
- object:[UIApplication sharedApplication]];
+ object:qt_apple_sharedApplication()];
#endif
}
@@ -453,7 +456,6 @@
focusWindow = qt_window_private(focusWindow)->topLevelWindow();
#ifndef Q_OS_TVOS
- UIApplication *uiApplication = [UIApplication sharedApplication];
// -------------- Status bar style and visbility ---------------
@@ -477,6 +479,8 @@
// -------------- Content orientation ---------------
+ UIApplication *uiApplication = qt_apple_sharedApplication();
+
static BOOL kAnimateContentOrientationChanges = YES;
Qt::ScreenOrientation contentOrientation = focusWindow->contentOrientation();
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h
index 3a3840f13c..d8cfd730ac 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.h
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.h
@@ -60,6 +60,8 @@ public:
void setGeometry(const QRect &rect) override;
+ QSurfaceFormat format() const override { return m_format; }
+
protected:
int pixelFormat() const override;
void resetBuffers() override;
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 80f3203289..980a9fe9ab 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -1430,7 +1430,7 @@ bool QWindowsContext::filterNativeEvent(MSG *msg, LRESULT *result)
bool QWindowsContext::filterNativeEvent(QWindow *window, MSG *msg, LRESULT *result)
{
long filterResult = 0;
- if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), &msg, &filterResult)) {
+ if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), msg, &filterResult)) {
*result = LRESULT(filterResult);
return true;
}
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index 6358778914..2409d70ec9 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -153,9 +153,11 @@ QT_BEGIN_NAMESPACE
QWindowsOpengl32DLL QOpenGLStaticContext::opengl32;
-FARPROC QWindowsOpengl32DLL::resolve(const char *name)
+QFunctionPointer QWindowsOpengl32DLL::resolve(const char *name)
{
- return m_lib ? ::GetProcAddress(m_lib, name) : nullptr;
+ return m_lib
+ ? reinterpret_cast<QFunctionPointer>(::GetProcAddress(m_lib, name))
+ : nullptr;
}
bool QWindowsOpengl32DLL::init(bool softwareRendering)
@@ -977,12 +979,18 @@ QOpenGLStaticContext::QOpenGLStaticContext() :
extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)),
extensions(0),
defaultFormat(QWindowsOpenGLContextFormat::current()),
- wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")),
- wglChoosePixelFormatARB((WglChoosePixelFormatARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")),
- wglCreateContextAttribsARB((WglCreateContextAttribsARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")),
- wglSwapInternalExt((WglSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")),
- wglGetSwapInternalExt((WglGetSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")),
- wglGetExtensionsStringARB((WglGetExtensionsStringARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB"))
+ wglGetPixelFormatAttribIVARB(reinterpret_cast<WglGetPixelFormatAttribIVARB>(
+ reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")))),
+ wglChoosePixelFormatARB(reinterpret_cast<WglChoosePixelFormatARB>(
+ reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")))),
+ wglCreateContextAttribsARB(reinterpret_cast<WglCreateContextAttribsARB>(
+ reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")))),
+ wglSwapInternalExt(reinterpret_cast<WglSwapInternalExt>(
+ reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")))),
+ wglGetSwapInternalExt(reinterpret_cast<WglGetSwapInternalExt>(
+ reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")))),
+ wglGetExtensionsStringARB(reinterpret_cast<WglGetExtensionsStringARB>(
+ reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB"))))
{
if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ")
|| extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1)
@@ -1231,7 +1239,8 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
hasRobustness = exts && strstr(exts, "GL_ARB_robustness");
} else {
typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint);
- glGetStringi_t glGetStringi = (glGetStringi_t) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi");
+ glGetStringi_t glGetStringi = reinterpret_cast<glGetStringi_t>(
+ reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi")));
if (glGetStringi) {
GLint n = 0;
QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n);
@@ -1244,8 +1253,10 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval)
}
}
}
- if (hasRobustness)
- m_getGraphicsResetStatus = (GLenum (APIENTRY *)()) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB");
+ if (hasRobustness) {
+ m_getGraphicsResetStatus = reinterpret_cast<GlGetGraphicsResetStatusArbType>(
+ reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB")));
+ }
QOpenGLStaticContext::opengl32.wglMakeCurrent(prevSurface, prevContext);
return true;
@@ -1369,16 +1380,17 @@ QFunctionPointer QWindowsGLContext::getProcAddress(const char *procName)
// Even though we use QFunctionPointer, it does not mean the function can be called.
// It will need to be cast to the proper function type with the correct calling
// convention. QFunctionPointer is nothing more than a glorified void* here.
- PROC procAddress = QOpenGLStaticContext::opengl32.wglGetProcAddress(procName);
+ QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName));
// We support AllGLFunctionsQueryable, which means this function must be able to
// return a function pointer even for functions that are in GL.h and exported
// normally from opengl32.dll. wglGetProcAddress() is not guaranteed to work for such
// functions, however in QT_OPENGL_DYNAMIC builds QOpenGLFunctions will just blindly
// call into here for _any_ OpenGL function.
- if (!procAddress || procAddress == reinterpret_cast<PROC>(0x1) || procAddress == reinterpret_cast<PROC>(0x2)
- || procAddress == reinterpret_cast<PROC>(0x3) || procAddress == reinterpret_cast<PROC>(-1))
+ if (procAddress == nullptr || reinterpret_cast<quintptr>(procAddress) < 4u
+ || procAddress == reinterpret_cast<QFunctionPointer>(-1)) {
procAddress = QOpenGLStaticContext::opengl32.resolve(procName);
+ }
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaGl) << __FUNCTION__ << procName << QOpenGLStaticContext::opengl32.wglGetCurrentContext() << "returns" << procAddress;
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h
index 2e89711740..8c96a8dd0c 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.h
+++ b/src/plugins/platforms/windows/qwindowsglcontext.h
@@ -122,7 +122,7 @@ struct QWindowsOpengl32DLL
void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params);
const GLubyte * (APIENTRY * glGetString)(GLenum name);
- FARPROC resolve(const char *name);
+ QFunctionPointer resolve(const char *name);
private:
HMODULE m_lib;
bool m_nonOpengl32;
@@ -217,6 +217,8 @@ public:
void *nativeContext() const override { return m_renderingContext; }
private:
+ typedef GLenum (APIENTRY *GlGetGraphicsResetStatusArbType)();
+
inline void releaseDCs();
bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = 0);
@@ -230,7 +232,7 @@ private:
bool m_extensionsUsed;
int m_swapInterval;
bool m_ownsContext;
- GLenum (APIENTRY * m_getGraphicsResetStatus)();
+ GlGetGraphicsResetStatusArbType m_getGraphicsResetStatus;
bool m_lost;
};
#endif
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 9f4dea915e..30da0da1de 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -163,19 +163,22 @@ Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id); // from qlocale_win.cpp
*/
-HIMC QWindowsInputContext::m_defaultContext = 0;
-
QWindowsInputContext::QWindowsInputContext() :
m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")),
m_languageId(currentInputLanguageId()),
m_locale(qt_localeFromLCID(m_languageId))
{
+ const quint32 bmpData = 0;
+ m_transparentBitmap = CreateBitmap(2, 2, 1, 1, &bmpData);
+
connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
this, &QWindowsInputContext::cursorRectChanged);
}
QWindowsInputContext::~QWindowsInputContext()
{
+ if (m_transparentBitmap)
+ DeleteObject(m_transparentBitmap);
}
bool QWindowsInputContext::hasCapability(Capability capability) const
@@ -242,6 +245,43 @@ bool QWindowsInputContext::isInputPanelVisible() const
return hwnd && ::IsWindowEnabled(hwnd) && ::IsWindowVisible(hwnd);
}
+void QWindowsInputContext::showInputPanel()
+{
+ if (!inputMethodAccepted())
+ return;
+
+ QWindow *window = QGuiApplication::focusWindow();
+ if (!window)
+ return;
+
+ QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window);
+ if (!platformWindow)
+ return;
+
+ // Create an invisible 2x2 caret, which will be kept at the microfocus position.
+ // It is important for triggering the on-screen keyboard in touch-screen devices,
+ // for some Chinese input methods, and for Magnifier's "follow keyboard" feature.
+ if (!m_caretCreated && m_transparentBitmap)
+ m_caretCreated = CreateCaret(platformWindow->handle(), m_transparentBitmap, 0, 0);
+
+ // For some reason, the on-screen keyboard is only triggered on the Surface
+ // with Windows 10 if the Windows IME is (re)enabled _after_ the caret is shown.
+ if (m_caretCreated) {
+ cursorRectChanged();
+ ShowCaret(platformWindow->handle());
+ setWindowsImeEnabled(platformWindow, false);
+ setWindowsImeEnabled(platformWindow, true);
+ }
+}
+
+void QWindowsInputContext::hideInputPanel()
+{
+ if (m_caretCreated) {
+ DestroyCaret();
+ m_caretCreated = false;
+ }
+}
+
void QWindowsInputContext::updateEnabled()
{
if (!QGuiApplication::focusObject())
@@ -256,18 +296,14 @@ void QWindowsInputContext::updateEnabled()
void QWindowsInputContext::setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled)
{
- if (!platformWindow || platformWindow->testFlag(QWindowsWindow::InputMethodDisabled) == !enabled)
+ if (!platformWindow)
return;
if (enabled) {
- // Re-enable Windows IME by associating default context saved on first disabling.
- ImmAssociateContext(platformWindow->handle(), QWindowsInputContext::m_defaultContext);
- platformWindow->clearFlag(QWindowsWindow::InputMethodDisabled);
+ // Re-enable Windows IME by associating default context.
+ ImmAssociateContextEx(platformWindow->handle(), 0, IACE_DEFAULT);
} else {
- // Disable Windows IME by associating 0 context. Store context first time.
- const HIMC oldImC = ImmAssociateContext(platformWindow->handle(), 0);
- platformWindow->setFlag(QWindowsWindow::InputMethodDisabled);
- if (!QWindowsInputContext::m_defaultContext && oldImC)
- QWindowsInputContext::m_defaultContext = oldImC;
+ // Disable Windows IME by associating 0 context.
+ ImmAssociateContext(platformWindow->handle(), 0);
}
}
@@ -284,15 +320,25 @@ void QWindowsInputContext::update(Qt::InputMethodQueries queries)
void QWindowsInputContext::cursorRectChanged()
{
- if (!m_compositionContext.hwnd)
+ QWindow *window = QGuiApplication::focusWindow();
+ if (!window)
return;
+
+ qreal factor = QHighDpiScaling::factor(window);
+
const QInputMethod *inputMethod = QGuiApplication::inputMethod();
const QRectF cursorRectangleF = inputMethod->cursorRectangle();
if (!cursorRectangleF.isValid())
return;
+
const QRect cursorRectangle =
- QRectF(cursorRectangleF.topLeft() * m_compositionContext.factor,
- cursorRectangleF.size() * m_compositionContext.factor).toRect();
+ QRectF(cursorRectangleF.topLeft() * factor, cursorRectangleF.size() * factor).toRect();
+
+ if (m_caretCreated)
+ SetCaretPos(cursorRectangle.x(), cursorRectangle.y());
+
+ if (!m_compositionContext.hwnd)
+ return;
qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle;
@@ -316,9 +362,6 @@ void QWindowsInputContext::cursorRectChanged()
candf.rcArea.right = cursorRectangle.x() + cursorRectangle.width();
candf.rcArea.bottom = cursorRectangle.y() + cursorRectangle.height();
- if (m_compositionContext.haveCaret)
- SetCaretPos(cursorRectangle.x(), cursorRectangle.y());
-
ImmSetCompositionWindow(himc, &cf);
ImmSetCandidateWindow(himc, &candf);
ImmReleaseContext(m_compositionContext.hwnd, himc);
@@ -410,7 +453,7 @@ bool QWindowsInputContext::startComposition(HWND hwnd)
qCDebug(lcQpaInputMethods) << __FUNCTION__ << fo << window << "language=" << m_languageId;
if (!fo || QWindowsWindow::handleOf(window) != hwnd)
return false;
- initContext(hwnd, QHighDpiScaling::factor(window), fo);
+ initContext(hwnd, fo);
startContextComposition();
return true;
}
@@ -550,18 +593,13 @@ bool QWindowsInputContext::endComposition(HWND hwnd)
return true;
}
-void QWindowsInputContext::initContext(HWND hwnd, qreal factor, QObject *focusObject)
+void QWindowsInputContext::initContext(HWND hwnd, QObject *focusObject)
{
if (m_compositionContext.hwnd)
doneContext();
m_compositionContext.hwnd = hwnd;
m_compositionContext.focusObject = focusObject;
- m_compositionContext.factor = factor;
- // Create a hidden caret which is kept at the microfocus
- // position in update(). This is important for some
- // Chinese input methods.
- m_compositionContext.haveCaret = CreateCaret(hwnd, 0, 1, 1);
- HideCaret(hwnd);
+
update(Qt::ImQueryAll);
m_compositionContext.isComposing = false;
m_compositionContext.position = 0;
@@ -571,12 +609,10 @@ void QWindowsInputContext::doneContext()
{
if (!m_compositionContext.hwnd)
return;
- if (m_compositionContext.haveCaret)
- DestroyCaret();
m_compositionContext.hwnd = 0;
m_compositionContext.composition.clear();
m_compositionContext.position = 0;
- m_compositionContext.isComposing = m_compositionContext.haveCaret = false;
+ m_compositionContext.isComposing = false;
m_compositionContext.focusObject = 0;
}
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h
index 35105d15ff..8668efbb15 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.h
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.h
@@ -58,12 +58,10 @@ class QWindowsInputContext : public QPlatformInputContext
struct CompositionContext
{
HWND hwnd = 0;
- bool haveCaret = false;
QString composition;
int position = 0;
bool isComposing = false;
QPointer<QObject> focusObject;
- qreal factor = 1;
};
public:
explicit QWindowsInputContext();
@@ -81,6 +79,8 @@ public:
QRectF keyboardRect() const override;
bool isInputPanelVisible() const override;
+ void showInputPanel() override;
+ void hideInputPanel() override;
bool startComposition(HWND hwnd);
bool composition(HWND hwnd, LPARAM lParam);
@@ -96,7 +96,7 @@ private slots:
void cursorRectChanged();
private:
- void initContext(HWND hwnd, qreal factor, QObject *focusObject);
+ void initContext(HWND hwnd, QObject *focusObject);
void doneContext();
void startContextComposition();
void endContextComposition();
@@ -104,7 +104,8 @@ private:
HWND getVirtualKeyboardWindowHandle() const;
const DWORD m_WM_MSIME_MOUSE;
- static HIMC m_defaultContext;
+ bool m_caretCreated = false;
+ HBITMAP m_transparentBitmap;
CompositionContext m_compositionContext;
bool m_endCompositionRecursionGuard = false;
LCID m_languageId;
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp
index a90a44c4e1..c4ee820211 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.cpp
+++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp
@@ -283,16 +283,21 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers()
bool QWindowsOpenGLTester::testDesktopGL()
{
#if !defined(QT_NO_OPENGL)
+ typedef HGLRC (WINAPI *CreateContextType)(HDC);
+ typedef BOOL (WINAPI *DeleteContextType)(HGLRC);
+ typedef BOOL (WINAPI *MakeCurrentType)(HDC, HGLRC);
+ typedef PROC (WINAPI *WglGetProcAddressType)(LPCSTR);
+
HMODULE lib = 0;
HWND wnd = 0;
HDC dc = 0;
HGLRC context = 0;
LPCTSTR className = L"qtopengltest";
- HGLRC (WINAPI * CreateContext)(HDC dc) = 0;
- BOOL (WINAPI * DeleteContext)(HGLRC context) = 0;
- BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context) = 0;
- PROC (WINAPI * WGL_GetProcAddress)(LPCSTR name) = 0;
+ CreateContextType CreateContext = nullptr;
+ DeleteContextType DeleteContext = nullptr;
+ MakeCurrentType MakeCurrent = nullptr;
+ WglGetProcAddressType WGL_GetProcAddress = nullptr;
bool result = false;
@@ -300,16 +305,20 @@ bool QWindowsOpenGLTester::testDesktopGL()
// This will typically fail on systems that do not have a real OpenGL driver.
lib = LoadLibraryA("opengl32.dll");
if (lib) {
- CreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(::GetProcAddress(lib, "wglCreateContext"));
+ CreateContext = reinterpret_cast<CreateContextType>(
+ reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "wglCreateContext")));
if (!CreateContext)
goto cleanup;
- DeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(::GetProcAddress(lib, "wglDeleteContext"));
+ DeleteContext = reinterpret_cast<DeleteContextType>(
+ reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "wglDeleteContext")));
if (!DeleteContext)
goto cleanup;
- MakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(::GetProcAddress(lib, "wglMakeCurrent"));
+ MakeCurrent = reinterpret_cast<MakeCurrentType>(
+ reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "wglMakeCurrent")));
if (!MakeCurrent)
goto cleanup;
- WGL_GetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(::GetProcAddress(lib, "wglGetProcAddress"));
+ WGL_GetProcAddress = reinterpret_cast<WglGetProcAddressType>(
+ reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "wglGetProcAddress")));
if (!WGL_GetProcAddress)
goto cleanup;
@@ -356,7 +365,8 @@ bool QWindowsOpenGLTester::testDesktopGL()
// Check the version. If we got 1.x then it's all hopeless and we can stop right here.
typedef const GLubyte * (APIENTRY * GetString_t)(GLenum name);
- GetString_t GetString = reinterpret_cast<GetString_t>(::GetProcAddress(lib, "glGetString"));
+ GetString_t GetString = reinterpret_cast<GetString_t>(
+ reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "glGetString")));
if (GetString) {
if (const char *versionStr = reinterpret_cast<const char *>(GetString(GL_VERSION))) {
const QByteArray version(versionStr);
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 02e986fd90..5ff25eb474 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -215,12 +215,11 @@ public:
WithinCreate = 0x20000,
WithinMaximize = 0x40000,
MaximizeToFullScreen = 0x80000,
- InputMethodDisabled = 0x100000,
- Compositing = 0x200000,
- HasBorderInFullScreen = 0x400000,
- WithinDpiChanged = 0x800000,
- VulkanSurface = 0x1000000,
- ResizeMoveActive = 0x2000000
+ Compositing = 0x100000,
+ HasBorderInFullScreen = 0x200000,
+ WithinDpiChanged = 0x400000,
+ VulkanSurface = 0x800000,
+ ResizeMoveActive = 0x1000000
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 8cfcc49f9a..b81cb8efa1 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -95,6 +95,9 @@ public:
void put(xcb_drawable_t dst, const QRegion &region, const QPoint &offset);
void preparePaint(const QRegion &region);
+ static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1,
+ xcb_shm_segment_info_t *shm_info = nullptr);
+
private:
void createShmSegment(size_t segmentSize);
void destroyShmSegment(size_t segmentSize);
@@ -325,15 +328,16 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize)
#ifdef XCB_USE_SHM_FD
if (connection()->hasShmFd()) {
if (Q_UNLIKELY(segmentSize > std::numeric_limits<uint32_t>::max())) {
- qWarning("QXcbShmImage: xcb_shm_create_segment() can't be called for size %zu, maximum allowed size is %u",
- segmentSize, std::numeric_limits<uint32_t>::max());
+ qCWarning(lcQpaXcb, "xcb_shm_create_segment() can't be called for size %zu, maximum"
+ "allowed size is %u", segmentSize, std::numeric_limits<uint32_t>::max());
return;
}
+
const auto seg = xcb_generate_id(xcb_connection());
auto reply = Q_XCB_REPLY(xcb_shm_create_segment,
xcb_connection(), seg, segmentSize, false);
if (!reply) {
- qWarning("QXcbShmImage: xcb_shm_create_segment() failed for size %zu", segmentSize);
+ qCWarning(lcQpaXcb, "xcb_shm_create_segment() failed for size %zu", segmentSize);
return;
}
@@ -342,13 +346,13 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize)
for (int i = 0; i < reply->nfd; i++)
close(fds[i]);
- qWarning("QXcbShmImage: failed to get file descriptor for shm segment of size %zu", segmentSize);
+ qCWarning(lcQpaXcb, "failed to get file descriptor for shm segment of size %zu", segmentSize);
return;
}
void *addr = mmap(nullptr, segmentSize, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0);
if (addr == MAP_FAILED) {
- qWarning("QXcbShmImage: failed to mmap segment from X server (%d: %s) for size %zu",
+ qCWarning(lcQpaXcb, "failed to mmap segment from X server (%d: %s) for size %zu",
errno, strerror(errno), segmentSize);
close(fds[0]);
xcb_shm_detach(xcb_connection(), seg);
@@ -358,47 +362,54 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize)
close(fds[0]);
m_shm_info.shmseg = seg;
m_shm_info.shmaddr = static_cast<quint8 *>(addr);
-
m_segmentSize = segmentSize;
} else
#endif
{
- const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600);
- if (id == -1) {
- qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %zu",
- errno, strerror(errno), segmentSize);
- return;
- }
-
- void *addr = shmat(id, 0, 0);
- if (addr == (void *)-1) {
- qWarning("QXcbShmImage: shmat() failed (%d: %s) for id %d",
- errno, strerror(errno), id);
- return;
- }
-
- if (shmctl(id, IPC_RMID, 0) == -1)
- qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed");
+ if (createSystemVShmSegment(connection(), segmentSize, &m_shm_info))
+ m_segmentSize = segmentSize;
+ }
+}
- const auto seg = xcb_generate_id(xcb_connection());
- auto cookie = xcb_shm_attach_checked(xcb_connection(), seg, id, false);
- auto *error = xcb_request_check(xcb_connection(), cookie);
- if (error) {
- connection()->printXcbError("QXcbShmImage: xcb_shm_attach() failed with error", error);
- free(error);
- if (shmdt(addr) == -1) {
- qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p",
- errno, strerror(errno), addr);
- }
- return;
- }
+bool QXcbBackingStoreImage::createSystemVShmSegment(QXcbConnection *c, size_t segmentSize,
+ xcb_shm_segment_info_t *shmInfo)
+{
+ const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600);
+ if (id == -1) {
+ qCWarning(lcQpaXcb, "shmget() failed (%d: %s) for size %zu", errno, strerror(errno), segmentSize);
+ return false;
+ }
- m_shm_info.shmseg = seg;
- m_shm_info.shmid = id; // unused
- m_shm_info.shmaddr = static_cast<quint8 *>(addr);
+ void *addr = shmat(id, 0, 0);
+ if (addr == (void *)-1) {
+ qCWarning(lcQpaXcb, "shmat() failed (%d: %s) for id %d", errno, strerror(errno), id);
+ return false;
+ }
- m_segmentSize = segmentSize;
+ if (shmctl(id, IPC_RMID, 0) == -1)
+ qCWarning(lcQpaXcb, "Error while marking the shared memory segment to be destroyed");
+
+ const auto seg = xcb_generate_id(c->xcb_connection());
+ auto cookie = xcb_shm_attach_checked(c->xcb_connection(), seg, id, false);
+ auto *error = xcb_request_check(c->xcb_connection(), cookie);
+ if (error) {
+ c->printXcbError("xcb_shm_attach() failed with error", error);
+ free(error);
+ if (shmdt(addr) == -1)
+ qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", errno, strerror(errno), addr);
+ return false;
+ } else if (!shmInfo) { // this was a test run, free the allocated test segment
+ xcb_shm_detach(c->xcb_connection(), seg);
+ auto shmaddr = static_cast<quint8 *>(addr);
+ if (shmdt(shmaddr) == -1)
+ qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", errno, strerror(errno), shmaddr);
+ }
+ if (shmInfo) {
+ shmInfo->shmseg = seg;
+ shmInfo->shmid = id; // unused
+ shmInfo->shmaddr = static_cast<quint8 *>(addr);
}
+ return true;
}
void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize)
@@ -409,21 +420,21 @@ void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize)
auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg);
xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
if (error)
- connection()->printXcbError("QXcbShmImage: xcb_shm_detach() failed with error", error);
+ connection()->printXcbError("xcb_shm_detach() failed with error", error);
m_shm_info.shmseg = 0;
#ifdef XCB_USE_SHM_FD
if (connection()->hasShmFd()) {
if (munmap(m_shm_info.shmaddr, segmentSize) == -1) {
- qWarning("QXcbShmImage: munmap() failed (%d: %s) for %p with size %zu",
- errno, strerror(errno), m_shm_info.shmaddr, segmentSize);
+ qCWarning(lcQpaXcb, "munmap() failed (%d: %s) for %p with size %zu",
+ errno, strerror(errno), m_shm_info.shmaddr, segmentSize);
}
} else
#endif
{
if (shmdt(m_shm_info.shmaddr) == -1) {
- qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p",
- errno, strerror(errno), m_shm_info.shmaddr);
+ qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p",
+ errno, strerror(errno), m_shm_info.shmaddr);
}
m_shm_info.shmid = 0; // unused
}
@@ -718,6 +729,12 @@ void QXcbBackingStoreImage::preparePaint(const QRegion &region)
m_pendingFlush |= region;
}
+bool QXcbBackingStore::createSystemVShmSegment(QXcbConnection *c, size_t segmentSize, void *shmInfo)
+{
+ auto info = reinterpret_cast<xcb_shm_segment_info_t *>(shmInfo);
+ return QXcbBackingStoreImage::createSystemVShmSegment(c, segmentSize, info);
+}
+
QXcbBackingStore::QXcbBackingStore(QWindow *window)
: QPlatformBackingStore(window)
{
@@ -757,7 +774,7 @@ void QXcbBackingStore::beginPaint(const QRegion &region)
void QXcbBackingStore::endPaint()
{
if (Q_UNLIKELY(m_paintRegions.isEmpty())) {
- qWarning("%s: paint regions empty!", Q_FUNC_INFO);
+ qCWarning(lcQpaXcb, "%s: paint regions empty!", Q_FUNC_INFO);
return;
}
@@ -811,7 +828,7 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
if (!platformWindow) {
- qWarning("QXcbBackingStore::flush: QWindow has no platform window (QTBUG-32681)");
+ qCWarning(lcQpaXcb, "%s QWindow has no platform window, see QTBUG-32681", Q_FUNC_INFO);
return;
}
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h
index 747626c213..734de1f7d7 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.h
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.h
@@ -74,6 +74,9 @@ public:
void beginPaint(const QRegion &) override;
void endPaint() override;
+ static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1,
+ void *shmInfo = nullptr);
+
private:
QXcbBackingStoreImage *m_image = nullptr;
QStack<QRegion> m_paintRegions;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 4ffeb4ff77..0e45b1efaf 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -56,6 +56,7 @@
#include "qxcbglintegrationfactory.h"
#include "qxcbglintegration.h"
#include "qxcbcursor.h"
+#include "qxcbbackingstore.h"
#include <QSocketNotifier>
#include <QAbstractEventDispatcher>
@@ -591,7 +592,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeAllAtoms();
initializeXSync();
- initializeShm();
+ if (!qEnvironmentVariableIsSet("QT_XCB_NO_MITSHM"))
+ initializeShm();
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR"))
initializeXRandr();
if (!has_randr_extension)
@@ -979,7 +981,7 @@ void QXcbConnection::printXcbError(const char *message, xcb_generic_error_t *err
uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
- qWarning("%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
+ qCWarning(lcQpaXcb, "%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
message,
int(error->error_code), xcb_errors[clamped_error_code],
int(error->sequence), int(error->resource_id),
@@ -1661,7 +1663,7 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
if (!hasXInput2())
return false;
- // compress XI_Motion, but not from tablet devices
+ // compress XI_Motion
if (isXIType(event, m_xiOpCode, XCB_INPUT_MOTION)) {
#if QT_CONFIG(tabletevent)
auto *xdev = reinterpret_cast<xcb_input_motion_event_t *>(event);
@@ -2074,20 +2076,34 @@ void QXcbConnection::initializeShm()
{
const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_shm_id);
if (!reply || !reply->present) {
- qWarning("QXcbConnection: MIT-SHM extension is not present on the X server.");
+ qCDebug(lcQpaXcb, "MIT-SHM extension is not present on the X server");
return;
}
-
has_shm = true;
auto shm_query = Q_XCB_REPLY(xcb_shm_query_version, m_connection);
- if (!shm_query) {
- qWarning("QXcbConnection: Failed to request MIT-SHM version");
- return;
+ if (shm_query) {
+ has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) ||
+ shm_query->major_version > 1;
+ } else {
+ qCWarning(lcQpaXcb, "QXcbConnection: Failed to request MIT-SHM version");
}
- has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) ||
- shm_query->major_version > 1;
+ qCDebug(lcQpaXcb) << "Has MIT-SHM :" << has_shm;
+ qCDebug(lcQpaXcb) << "Has MIT-SHM FD :" << has_shm_fd;
+
+ // Temporary disable warnings (unless running in debug mode).
+ auto logging = const_cast<QLoggingCategory*>(&lcQpaXcb());
+ bool wasEnabled = logging->isEnabled(QtMsgType::QtWarningMsg);
+ if (!logging->isEnabled(QtMsgType::QtDebugMsg))
+ logging->setEnabled(QtMsgType::QtWarningMsg, false);
+ if (!QXcbBackingStore::createSystemVShmSegment(this)) {
+ qCDebug(lcQpaXcb, "failed to create System V shared memory segment (remote "
+ "X11 connection?), disabling SHM");
+ has_shm = has_shm_fd = false;
+ }
+ if (wasEnabled)
+ logging->setEnabled(QtMsgType::QtWarningMsg, true);
}
void QXcbConnection::initializeXFixes()
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 475afa65db..7ed61bff4e 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -1017,6 +1017,7 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
std::swap(angleDelta.rx(), angleDelta.ry());
std::swap(rawDelta.rx(), rawDelta.ry());
}
+ qCDebug(lcQpaXInputEvents) << "scroll wheel @ window pos" << local << "delta px" << rawDelta << "angle" << angleDelta;
QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, rawDelta, angleDelta, modifiers);
}
}
@@ -1041,6 +1042,7 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective);
if (modifiers & Qt::AltModifier)
std::swap(angleDelta.rx(), angleDelta.ry());
+ qCDebug(lcQpaXInputEvents) << "scroll wheel (button" << xiDeviceEvent->detail << ") @ window pos" << local << "delta angle" << angleDelta;
QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, QPoint(), angleDelta, modifiers);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index d9cddef2d2..3ad16d78d9 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -136,6 +136,13 @@ static const unsigned int KeyTbl[] = {
XKB_KEY_KP_Decimal, Qt::Key_Period,
XKB_KEY_KP_Divide, Qt::Key_Slash,
+ // special non-XF86 function keys
+
+ XKB_KEY_Undo, Qt::Key_Undo,
+ XKB_KEY_Redo, Qt::Key_Redo,
+ XKB_KEY_Find, Qt::Key_Find,
+ XKB_KEY_Cancel, Qt::Key_Cancel,
+
// International input method support keys
// International & multi-key character composition
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 3b440bbb71..dd7e054301 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -744,12 +744,7 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation)
m_sizeMillimeters = sizeInMillimeters(geometry.size(), virtualDpi());
qreal dpi = geometry.width() / physicalSize().width() * qreal(25.4);
- qreal rawFactor = dpi/96;
- int roundedFactor = qFloor(rawFactor);
- // Round up for .8 and higher. This favors "small UI" over "large UI".
- if (rawFactor - roundedFactor >= 0.8)
- roundedFactor = qCeil(rawFactor);
- m_pixelDensity = qMax(1, roundedFactor);
+ m_pixelDensity = qMax(1, qRound(dpi/96));
m_geometry = geometry;
m_availableGeometry = geometry & m_virtualDesktop->workArea();
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 3c2d4edc4d..9192f1d9e4 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -2200,15 +2200,15 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
quint8 mode, quint8 detail, xcb_timestamp_t timestamp)
{
connection()->setTime(timestamp);
-#if QT_CONFIG(xcb_xinput)
- // Updates scroll valuators, as user might have done some scrolling outside our X client.
- connection()->xi2UpdateScrollingDevices();
-#endif
const QPoint global = QPoint(root_x, root_y);
if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
return;
+#if QT_CONFIG(xcb_xinput)
+ // Updates scroll valuators, as user might have done some scrolling outside our X client.
+ connection()->xi2UpdateScrollingDevices();
+#endif
const QPoint local(event_x, event_y);
QWindowSystemInterface::handleEnterEvent(window(), local, global);
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
index 484dad6e1d..ead08dbce8 100644
--- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
+++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
@@ -1845,9 +1845,11 @@ bool QIBaseDriver::subscribeToNotification(const QString &name)
eBuffer->bufferLength,
eBuffer->eventBuffer,
#if defined (FB_API_VER) && FB_API_VER >= 20
- reinterpret_cast<ISC_EVENT_CALLBACK>(qEventCallback),
+ reinterpret_cast<ISC_EVENT_CALLBACK>(reinterpret_cast<void *>
+ (&qEventCallback)),
#else
- reinterpret_cast<isc_callback>(qEventCallback),
+ reinterpret_cast<isc_callback>(reinterpret_cast<void *>
+ (&qEventCallback)),
#endif
eBuffer->resultBuffer);
@@ -1925,9 +1927,11 @@ void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer)
eBuffer->bufferLength,
eBuffer->eventBuffer,
#if defined (FB_API_VER) && FB_API_VER >= 20
- reinterpret_cast<ISC_EVENT_CALLBACK>(qEventCallback),
+ reinterpret_cast<ISC_EVENT_CALLBACK>(reinterpret_cast<void *>
+ (&qEventCallback)),
#else
- reinterpret_cast<isc_callback>(qEventCallback),
+ reinterpret_cast<isc_callback>(reinterpret_cast<void *>
+ (&qEventCallback)),
#endif
eBuffer->resultBuffer);
if (Q_UNLIKELY(status[0] == 1 && status[1])) {
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index bb5f25e4d7..60fe547807 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -238,24 +238,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QVerticalSplitView);
}
@end
-#if !QT_CONFIG(appstore_compliant)
-
-// This API was requested to Apple in rdar #36197888.
-// We know it's safe to use up to macOS 10.13.3.
-// See drawComplexControl(CC_ComboBox) for its usage.
-
-@interface NSComboBoxCell (QtButtonCell)
-@property (readonly) NSButtonCell *qt_buttonCell;
-@end
-
-@implementation NSComboBoxCell (QtButtonCell)
-- (NSButtonCell *)qt_buttonCell {
- return self->_buttonCell;
-}
-@end
-
-#endif
-
QT_BEGIN_NAMESPACE
// The following constants are used for adjusting the size
@@ -5205,11 +5187,14 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
auto *cb = static_cast<NSComboBox *>(cc);
const auto frameRect = cw.adjustedControlFrame(combo->rect);
cb.frame = frameRect.toCGRect();
-#if !QT_CONFIG(appstore_compliant)
- static_cast<NSComboBoxCell *>(cc.cell).qt_buttonCell.highlighted = isPressed;
-#else
- // TODO Render to pixmap and darken the button manually
-#endif
+
+ // This API was requested to Apple in rdar #36197888. We know it's safe to use up to macOS 10.13.3
+ if (NSButtonCell *cell = static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@"_buttonCell"])) {
+ cell.highlighted = isPressed;
+ } else {
+ // TODO Render to pixmap and darken the button manually
+ }
+
d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef __unused ctx, const CGRect &r) {
// FIXME This is usually drawn in the control's superview, but we wouldn't get inactive look in this case
[cb.cell drawWithFrame:r inView:cb];
diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
index e690a424ac..4b583e13d3 100644
--- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
+++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp
@@ -944,7 +944,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa
if (!isCached) {
// SHORTCUT: If the part's state has no data, cache it for NOOP later
if (!stateHasData) {
- memset(&data, 0, sizeof(data));
+ memset(static_cast<void *>(&data), 0, sizeof(data));
data.dataValid = true;
alphaCache.insert(key, data);
return true;
@@ -1051,7 +1051,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa
// Add to theme part cache
if (!isCached) {
- memset(&data, 0, sizeof(data));
+ memset(static_cast<void *>(&data), 0, sizeof(data));
data.dataValid = true;
data.partIsTransparent = partIsTransparent;
data.alphaType = alphaType;
diff --git a/src/src.pro b/src/src.pro
index 1f7c5d99c1..1c76a2e46f 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -53,6 +53,10 @@ src_tools_qdbuscpp2xml.target = sub-qdbuscpp2xml
force_bootstrap: src_tools_qdbuscpp2xml.depends = src_tools_bootstrap_dbus
else: src_tools_qdbuscpp2xml.depends = src_dbus
+src_tools_androiddeployqt.subdir = tools/androiddeployqt
+src_tools_androiddeployqt.target = sub-androiddeployqt
+src_tools_androiddeployqt.depends = src_corelib
+
src_tools_qvkgen.subdir = tools/qvkgen
src_tools_qvkgen.target = sub-qvkgen
force_bootstrap: src_tools_qvkgen.depends = src_tools_bootstrap
@@ -183,6 +187,12 @@ qtConfig(dbus) {
src_platformsupport.depends += src_dbus src_tools_qdbusxml2cpp
src_plugins.depends += src_dbus src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml
}
+
+android {
+ SUBDIRS += src_tools_androiddeployqt
+ TOOLS += src_tools_androiddeployqt
+}
+
qtConfig(concurrent): SUBDIRS += src_concurrent
qtConfig(gui) {
qtConfig(harfbuzz):!qtConfig(system-harfbuzz) {
diff --git a/src/testlib/qabstractitemmodeltester.cpp b/src/testlib/qabstractitemmodeltester.cpp
index e970be2c8d..fc6f696ecd 100644
--- a/src/testlib/qabstractitemmodeltester.cpp
+++ b/src/testlib/qabstractitemmodeltester.cpp
@@ -322,9 +322,10 @@ void QAbstractItemModelTesterPrivate::nonDestructiveBasicTest()
Qt::ItemFlags flags = model->flags(QModelIndex());
MODELTESTER_VERIFY(flags == Qt::ItemIsDropEnabled || flags == 0);
model->hasChildren(QModelIndex());
- model->hasIndex(0, 0);
+ const bool hasRow = model->hasIndex(0, 0);
QVariant cache;
- model->match(QModelIndex(), -1, cache);
+ if (hasRow)
+ model->match(model->index(0, 0), -1, cache);
model->mimeTypes();
MODELTESTER_VERIFY(!model->parent(QModelIndex()).isValid());
MODELTESTER_VERIFY(model->rowCount() >= 0);
@@ -712,8 +713,17 @@ void QAbstractItemModelTesterPrivate::rowsAboutToBeRemoved(const QModelIndex &pa
Changing c;
c.parent = parent;
c.oldSize = model->rowCount(parent);
- c.last = model->data(model->index(start - 1, 0, parent));
- c.next = model->data(model->index(end + 1, 0, parent));
+ if (start > 0) {
+ const QModelIndex startIndex = model->index(start - 1, 0, parent);
+ MODELTESTER_VERIFY(startIndex.isValid());
+ c.last = model->data(startIndex);
+ }
+ if (end < c.oldSize - 1) {
+ const QModelIndex endIndex = model->index(end + 1, 0, parent);
+ MODELTESTER_VERIFY(endIndex.isValid());
+ c.next = model->data(endIndex);
+ }
+
remove.push(c);
}
@@ -732,8 +742,10 @@ void QAbstractItemModelTesterPrivate::rowsRemoved(const QModelIndex &parent, int
Changing c = remove.pop();
MODELTESTER_COMPARE(parent, c.parent);
MODELTESTER_COMPARE(model->rowCount(parent), c.oldSize - (end - start + 1));
- MODELTESTER_COMPARE(model->data(model->index(start - 1, 0, c.parent)), c.last);
- MODELTESTER_COMPARE(model->data(model->index(start, 0, c.parent)), c.next);
+ if (start > 0)
+ MODELTESTER_COMPARE(model->data(model->index(start - 1, 0, c.parent)), c.last);
+ if (end < c.oldSize - 1)
+ MODELTESTER_COMPARE(model->data(model->index(start, 0, c.parent)), c.next);
}
void QAbstractItemModelTesterPrivate::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
diff --git a/src/testlib/qabstractitemmodeltester.h b/src/testlib/qabstractitemmodeltester.h
index 07bc170a7a..757074c6ae 100644
--- a/src/testlib/qabstractitemmodeltester.h
+++ b/src/testlib/qabstractitemmodeltester.h
@@ -42,6 +42,8 @@
#include <QtCore/QObject>
#include <QtTest/qttestglobal.h>
+#include <QtCore/QAbstractItemModel>
+#include <QtCore/QVariant>
#ifdef QT_GUI_LIB
#include <QtGui/QFont>
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index 469c423109..7a74afce91 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -1634,8 +1634,10 @@ DebugSymbolResolver::DebugSymbolResolver(HANDLE process)
bool success = false;
m_dbgHelpLib = LoadLibraryW(L"dbghelp.dll");
if (m_dbgHelpLib) {
- SymInitializeType symInitialize = (SymInitializeType)(GetProcAddress(m_dbgHelpLib, "SymInitialize"));
- m_symFromAddr = (SymFromAddrType)(GetProcAddress(m_dbgHelpLib, "SymFromAddr"));
+ SymInitializeType symInitialize = reinterpret_cast<SymInitializeType>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(m_dbgHelpLib, "SymInitialize")));
+ m_symFromAddr = reinterpret_cast<SymFromAddrType>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(m_dbgHelpLib, "SymFromAddr")));
success = symInitialize && m_symFromAddr && symInitialize(process, NULL, TRUE);
}
if (!success)
@@ -2166,8 +2168,9 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co
srcdir.setFile(QFile::decodeName(builddir) + QLatin1String("/") + srcdir.filePath());
}
- QString candidate = QString::fromLatin1("%1/%2").arg(srcdir.canonicalFilePath(), base);
- if (QFileInfo::exists(candidate)) {
+ const QString canonicalPath = srcdir.canonicalFilePath();
+ QString candidate = QString::fromLatin1("%1/%2").arg(canonicalPath, base);
+ if (!canonicalPath.isEmpty() && QFileInfo::exists(candidate)) {
found = candidate;
}
else if (QTestLog::verboseLevel() >= 2) {
diff --git a/src/tools/androiddeployqt/androiddeployqt.pro b/src/tools/androiddeployqt/androiddeployqt.pro
new file mode 100644
index 0000000000..2d0f5b41d1
--- /dev/null
+++ b/src/tools/androiddeployqt/androiddeployqt.pro
@@ -0,0 +1,14 @@
+option(host_build)
+CONFIG += console
+
+SOURCES += \
+ main.cpp
+
+# Required for declarations of popen/pclose on Windows
+windows: QMAKE_CXXFLAGS += -U__STRICT_ANSI__
+
+DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
+DEFINES += QT_NO_FOREACH
+
+load(qt_app)
+
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
new file mode 100644
index 0000000000..ebd9480808
--- /dev/null
+++ b/src/tools/androiddeployqt/main.cpp
@@ -0,0 +1,2912 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QStringList>
+#include <QDir>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QJsonValue>
+#include <QDebug>
+#include <QDataStream>
+#include <QXmlStreamReader>
+#include <QDateTime>
+#include <QStandardPaths>
+#include <QUuid>
+#include <QDirIterator>
+#include <QRegExp>
+
+#include <algorithm>
+static const bool mustReadOutputAnyway = true; // pclose seems to return the wrong error code unless we read the output
+
+void deleteRecursively(const QString &dirName)
+{
+ QDir dir(dirName);
+ if (!dir.exists())
+ return;
+
+ const QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
+ for (const QFileInfo &entry : entries) {
+ if (entry.isDir())
+ deleteRecursively(entry.absoluteFilePath());
+ else
+ QFile::remove(entry.absoluteFilePath());
+ }
+
+ QDir().rmdir(dirName);
+}
+
+FILE *openProcess(const QString &command)
+{
+#if defined(Q_OS_WIN32)
+ QString processedCommand = QLatin1Char('\"') + command + QLatin1Char('\"');
+#else
+ QString processedCommand = command;
+#endif
+
+ return popen(processedCommand.toLocal8Bit().constData(), "r");
+}
+
+struct QtDependency
+{
+ QtDependency(QString rpath, QString apath) : relativePath(rpath), absolutePath(apath) {}
+
+ bool operator==(const QtDependency &other) const
+ {
+ return relativePath == other.relativePath && absolutePath == other.absolutePath;
+ }
+
+ QString relativePath;
+ QString absolutePath;
+};
+
+struct Options
+{
+ Options()
+ : helpRequested(false)
+ , verbose(false)
+ , timing(false)
+ , generateAssetsFileList(true)
+ , build(true)
+ , gradle(false)
+ , deploymentMechanism(Bundled)
+ , releasePackage(false)
+ , digestAlg(QLatin1String("SHA1"))
+ , sigAlg(QLatin1String("SHA1withRSA"))
+ , internalSf(false)
+ , sectionsOnly(false)
+ , protectedAuthenticationPath(false)
+ , jarSigner(false)
+ , gdbServer(Auto)
+ , installApk(false)
+ , uninstallApk(false)
+ {}
+
+ enum DeploymentMechanism
+ {
+ Bundled,
+ Ministro
+ };
+
+ enum TriState {
+ Auto,
+ False,
+ True
+ };
+
+ bool helpRequested;
+ bool verbose;
+ bool timing;
+ bool generateAssetsFileList;
+ bool build;
+ bool gradle;
+ QTime timer;
+
+ // External tools
+ QString sdkPath;
+ QString sdkBuildToolsVersion;
+ QString ndkPath;
+ QString antTool;
+ QString jdkPath;
+
+ // Build paths
+ QString qtInstallDirectory;
+ QString androidSourceDirectory;
+ QString outputDirectory;
+ QString inputFileName;
+ QString applicationBinary;
+ QString rootPath;
+ QStringList qmlImportPaths;
+
+ // lib c++ path
+ QString stdCppPath;
+ QString stdCppName = QStringLiteral("gnustl_shared");
+
+ // Build information
+ QString androidPlatform;
+ QString architecture;
+ QString toolchainVersion;
+ QString toolchainPrefix;
+ QString toolPrefix;
+ QString ndkHost;
+
+ // Package information
+ DeploymentMechanism deploymentMechanism;
+ QString packageName;
+ QStringList extraLibs;
+ QStringList extraPlugins;
+
+ // Signing information
+ bool releasePackage;
+ QString keyStore;
+ QString keyStorePassword;
+ QString keyStoreAlias;
+ QString storeType;
+ QString keyPass;
+ QString sigFile;
+ QString signedJar;
+ QString digestAlg;
+ QString sigAlg;
+ QString tsaUrl;
+ QString tsaCert;
+ bool internalSf;
+ bool sectionsOnly;
+ bool protectedAuthenticationPath;
+ bool jarSigner;
+
+ // Gdbserver
+ TriState gdbServer;
+
+ // Installation information
+ bool installApk;
+ bool uninstallApk;
+ QString installLocation;
+
+ // Collected information
+ typedef QPair<QString, QString> BundledFile;
+ QList<BundledFile> bundledFiles;
+ QList<QtDependency> qtDependencies;
+ QStringList localLibs;
+ QStringList localJars;
+ QStringList initClasses;
+ QStringList permissions;
+ QStringList features;
+};
+
+// Copy-pasted from qmake/library/ioutil.cpp
+inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
+{
+ for (int x = arg.length() - 1; x >= 0; --x) {
+ ushort c = arg.unicode()[x].unicode();
+ if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
+ return true;
+ }
+ return false;
+}
+
+static QString shellQuoteUnix(const QString &arg)
+{
+ // Chars that should be quoted (TM). This includes:
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
+ 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
+ }; // 0-32 \'"$`<>|;&(){}*?#!~[]
+
+ if (!arg.length())
+ return QString::fromLatin1("\"\"");
+
+ QString ret(arg);
+ if (hasSpecialChars(ret, iqm)) {
+ ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
+ ret.prepend(QLatin1Char('\''));
+ ret.append(QLatin1Char('\''));
+ }
+ return ret;
+}
+
+static QString shellQuoteWin(const QString &arg)
+{
+ // Chars that should be quoted (TM). This includes:
+ // - control chars & space
+ // - the shell meta chars "&()<>^|
+ // - the potential separators ,;=
+ static const uchar iqm[] = {
+ 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
+ };
+
+ if (!arg.length())
+ return QString::fromLatin1("\"\"");
+
+ QString ret(arg);
+ if (hasSpecialChars(ret, iqm)) {
+ // Quotes are escaped and their preceding backslashes are doubled.
+ // It's impossible to escape anything inside a quoted string on cmd
+ // level, so the outer quoting must be "suspended".
+ ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\""));
+ // The argument must not end with a \ since this would be interpreted
+ // as escaping the quote -- rather put the \ behind the quote: e.g.
+ // rather use "foo"\ than "foo\"
+ int i = ret.length();
+ while (i > 0 && ret.at(i - 1) == QLatin1Char('\\'))
+ --i;
+ ret.insert(i, QLatin1Char('"'));
+ ret.prepend(QLatin1Char('"'));
+ }
+ return ret;
+}
+
+static QString shellQuote(const QString &arg)
+{
+ if (QDir::separator() == QLatin1Char('\\'))
+ return shellQuoteWin(arg);
+ else
+ return shellQuoteUnix(arg);
+}
+
+
+void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &dstDir)
+{
+ if (options.verbose)
+ fprintf(stdout, "Delete missing files %s %s\n", qPrintable(srcDir.absolutePath()), qPrintable(dstDir.absolutePath()));
+
+ const QFileInfoList srcEntries = srcDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
+ const QFileInfoList dstEntries = dstDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
+ for (const QFileInfo &dst : dstEntries) {
+ bool found = false;
+ for (const QFileInfo &src : srcEntries)
+ if (dst.fileName() == src.fileName()) {
+ if (dst.isDir())
+ deleteMissingFiles(options, src.absoluteFilePath(), dst.absoluteFilePath());
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ if (options.verbose)
+ fprintf(stdout, "%s not found in %s, removing it.\n", qPrintable(dst.fileName()), qPrintable(srcDir.absolutePath()));
+
+ if (dst.isDir())
+ deleteRecursively(dst.absolutePath());
+ else
+ QFile::remove(dst.absoluteFilePath());
+ }
+ }
+ fflush(stdout);
+}
+
+
+Options parseOptions()
+{
+ Options options;
+
+ QStringList arguments = QCoreApplication::arguments();
+ for (int i=0; i<arguments.size(); ++i) {
+ const QString &argument = arguments.at(i);
+ if (argument.compare(QLatin1String("--output"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.outputDirectory = arguments.at(++i).trimmed();
+ } else if (argument.compare(QLatin1String("--input"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.inputFileName = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--no-build"), Qt::CaseInsensitive) == 0) {
+ options.build = false;
+ } else if (argument.compare(QLatin1String("--install"), Qt::CaseInsensitive) == 0) {
+ options.installApk = true;
+ options.uninstallApk = true;
+ } else if (argument.compare(QLatin1String("--reinstall"), Qt::CaseInsensitive) == 0) {
+ options.installApk = true;
+ options.uninstallApk = false;
+ } else if (argument.compare(QLatin1String("--android-platform"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.androidPlatform = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--help"), Qt::CaseInsensitive) == 0) {
+ options.helpRequested = true;
+ } else if (argument.compare(QLatin1String("--verbose"), Qt::CaseInsensitive) == 0) {
+ options.verbose = true;
+ } else if (argument.compare(QLatin1String("--gradle"), Qt::CaseInsensitive) == 0) {
+ options.gradle = true;
+ } else if (argument.compare(QLatin1String("--ant"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.antTool = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--deployment"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size()) {
+ options.helpRequested = true;
+ } else {
+ QString deploymentMechanism = arguments.at(++i);
+ if (deploymentMechanism.compare(QLatin1String("ministro"), Qt::CaseInsensitive) == 0) {
+ options.deploymentMechanism = Options::Ministro;
+ } else if (deploymentMechanism.compare(QLatin1String("bundled"), Qt::CaseInsensitive) == 0) {
+ options.deploymentMechanism = Options::Bundled;
+ } else {
+ fprintf(stderr, "Unrecognized deployment mechanism: %s\n", qPrintable(deploymentMechanism));
+ options.helpRequested = true;
+ }
+ }
+ } else if (argument.compare(QLatin1String("--device"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.installLocation = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--release"), Qt::CaseInsensitive) == 0) {
+ options.releasePackage = true;
+ } else if (argument.compare(QLatin1String("--gdbserver"), Qt::CaseInsensitive) == 0) {
+ options.gdbServer = Options::True;
+ } else if (argument.compare(QLatin1String("--no-gdbserver"), Qt::CaseInsensitive) == 0) {
+ options.gdbServer = Options::False;
+ } else if (argument.compare(QLatin1String("--jdk"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.jdkPath = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--sign"), Qt::CaseInsensitive) == 0) {
+ if (i + 2 >= arguments.size()) {
+ options.helpRequested = true;
+ } else {
+ options.releasePackage = true;
+ options.keyStore = arguments.at(++i);
+ options.keyStoreAlias = arguments.at(++i);
+ }
+ } else if (argument.compare(QLatin1String("--storepass"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.keyStorePassword = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--storetype"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.storeType = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--keypass"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.keyPass = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--sigfile"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.sigFile = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--digestalg"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.digestAlg = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--sigalg"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.sigAlg = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--tsa"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.tsaUrl = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--tsacert"), Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ options.helpRequested = true;
+ else
+ options.tsaCert = arguments.at(++i);
+ } else if (argument.compare(QLatin1String("--internalsf"), Qt::CaseInsensitive) == 0) {
+ options.internalSf = true;
+ } else if (argument.compare(QLatin1String("--sectionsonly"), Qt::CaseInsensitive) == 0) {
+ options.sectionsOnly = true;
+ } else if (argument.compare(QLatin1String("--protected"), Qt::CaseInsensitive) == 0) {
+ options.protectedAuthenticationPath = true;
+ } else if (argument.compare(QLatin1String("--jarsigner"), Qt::CaseInsensitive) == 0) {
+ options.jarSigner = true;
+ } else if (argument.compare(QLatin1String("--no-generated-assets-cache"), Qt::CaseInsensitive) == 0) {
+ options.generateAssetsFileList = false;
+ }
+ }
+
+ if (options.inputFileName.isEmpty())
+ options.inputFileName = QString::fromLatin1("android-lib%1.so-deployment-settings.json").arg(QDir::current().dirName());
+
+ options.timing = qEnvironmentVariableIsSet("ANDROIDDEPLOYQT_TIMING_OUTPUT");
+
+ if (!QDir::current().mkpath(options.outputDirectory)) {
+ fprintf(stderr, "Invalid output directory: %s\n", qPrintable(options.outputDirectory));
+ options.outputDirectory.clear();
+ } else {
+ options.outputDirectory = QFileInfo(options.outputDirectory).canonicalFilePath();
+ if (!options.outputDirectory.endsWith(QLatin1Char('/')))
+ options.outputDirectory += QLatin1Char('/');
+ }
+
+ return options;
+}
+
+void printHelp()
+{// "012345678901234567890123456789012345678901234567890123456789012345678901"
+ fprintf(stderr, "Syntax: %s --output <destination> [options]\n"
+ "\n"
+ " Creates an Android package in the build directory <destination> and\n"
+ " builds it into an .apk file.\n\n"
+ " Optional arguments:\n"
+ " --input <inputfile>: Reads <inputfile> for options generated by\n"
+ " qmake. A default file name based on the current working\n"
+ " directory will be used if nothing else is specified.\n"
+ " --deployment <mechanism>: Supported deployment mechanisms:\n"
+ " bundled (default): Include Qt files in stand-alone package.\n"
+ " ministro: Use the Ministro service to manage Qt files.\n"
+ " --no-build: Do not build the package, it is useful to just install\n"
+ " a package previously built.\n"
+ " --install: Installs apk to device/emulator. By default this step is\n"
+ " not taken. If the application has previously been installed on\n"
+ " the device, it will be uninstalled first.\n"
+ " --reinstall: Installs apk to device/emulator. By default this step\n"
+ " is not taken. If the application has previously been installed on\n"
+ " the device, it will be overwritten, but its data will be left\n"
+ " intact.\n"
+ " --device [device ID]: Use specified device for deployment. Default\n"
+ " is the device selected by default by adb.\n"
+ " --android-platform <platform>: Builds against the given android\n"
+ " platform. By default, the highest available version will be\n"
+ " used.\n"
+ " --gradle. Use gradle instead of ant to create and install the apk.\n"
+ " --ant <path/to/ant>: If unspecified, ant from the PATH will be\n"
+ " used.\n"
+ " --release: Builds a package ready for release. By default, the\n"
+ " package will be signed with a debug key.\n"
+ " --sign <url/to/keystore> <alias>: Signs the package with the\n"
+ " specified keystore, alias and store password. Also implies the\n"
+ " --release option.\n"
+ " Optional arguments for use with signing:\n"
+ " --storepass <password>: Keystore password.\n"
+ " --storetype <type>: Keystore type.\n"
+ " --keypass <password>: Password for private key (if different\n"
+ " from keystore password.)\n"
+ " --sigfile <file>: Name of .SF/.DSA file.\n"
+ " --digestalg <name>: Name of digest algorithm. Default is\n"
+ " \"SHA1\".\n"
+ " --sigalg <name>: Name of signature algorithm. Default is\n"
+ " \"SHA1withRSA\".\n"
+ " --tsa <url>: Location of the Time Stamping Authority.\n"
+ " --tsacert <alias>: Public key certificate for TSA.\n"
+ " --internalsf: Include the .SF file inside the signature block.\n"
+ " --sectionsonly: Don't compute hash of entire manifest.\n"
+ " --protected: Keystore has protected authentication path.\n"
+ " --jarsigner: Force jarsigner usage, otherwise apksigner will be\n"
+ " used if available.\n"
+ " --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n"
+ " is bundled for debug pacakges.\n"
+ " --no-gdbserver: Prevents the gdbserver from being added to the package\n"
+ " By default the gdbserver is bundled for debug pacakges.\n"
+ " --jdk <path/to/jdk>: Used to find the jarsigner tool when used\n"
+ " in combination with the --release argument. By default,\n"
+ " an attempt is made to detect the tool using the JAVA_HOME and\n"
+ " PATH environment variables, in that order.\n"
+ " --qml-import-paths: Specify additional search paths for QML\n"
+ " imports.\n"
+ " --verbose: Prints out information during processing.\n"
+ " --no-generated-assets-cache: Do not pregenerate the entry list for\n"
+ " the assets file engine.\n"
+ " --help: Displays this information.\n\n",
+ qPrintable(QCoreApplication::arguments().at(0))
+ );
+}
+
+// Since strings compared will all start with the same letters,
+// sorting by length and then alphabetically within each length
+// gives the natural order.
+bool quasiLexicographicalReverseLessThan(const QFileInfo &fi1, const QFileInfo &fi2)
+{
+ QString s1 = fi1.baseName();
+ QString s2 = fi2.baseName();
+
+ if (s1.length() == s2.length())
+ return s1 > s2;
+ else
+ return s1.length() > s2.length();
+}
+
+// Files which contain templates that need to be overwritten by build data should be overwritten every
+// time.
+bool alwaysOverwritableFile(const QString &fileName)
+{
+ return (fileName.endsWith(QLatin1String("/res/values/libs.xml"))
+ || fileName.endsWith(QLatin1String("/AndroidManifest.xml"))
+ || fileName.endsWith(QLatin1String("/res/values/strings.xml"))
+ || fileName.endsWith(QLatin1String("/src/org/qtproject/qt5/android/bindings/QtActivity.java")));
+}
+
+bool copyFileIfNewer(const QString &sourceFileName,
+ const QString &destinationFileName,
+ bool verbose,
+ bool forceOverwrite = false)
+{
+ if (QFile::exists(destinationFileName)) {
+ QFileInfo destinationFileInfo(destinationFileName);
+ QFileInfo sourceFileInfo(sourceFileName);
+
+ if (!forceOverwrite
+ && sourceFileInfo.lastModified() <= destinationFileInfo.lastModified()
+ && !alwaysOverwritableFile(destinationFileName)) {
+ if (verbose)
+ fprintf(stdout, " -- Skipping file %s. Same or newer file already in place.\n", qPrintable(sourceFileName));
+ return true;
+ } else {
+ if (!QFile(destinationFileName).remove()) {
+ fprintf(stderr, "Can't remove old file: %s\n", qPrintable(destinationFileName));
+ return false;
+ }
+ }
+ }
+
+ if (!QDir().mkpath(QFileInfo(destinationFileName).path())) {
+ fprintf(stderr, "Cannot make output directory for %s.\n", qPrintable(destinationFileName));
+ return false;
+ }
+
+ if (!QFile::exists(destinationFileName) && !QFile::copy(sourceFileName, destinationFileName)) {
+ fprintf(stderr, "Failed to copy %s to %s.\n", qPrintable(sourceFileName), qPrintable(destinationFileName));
+ return false;
+ } else if (verbose) {
+ fprintf(stdout, " -- Copied %s\n", qPrintable(destinationFileName));
+ fflush(stdout);
+ }
+
+ return true;
+}
+
+QString cleanPackageName(QString packageName)
+{
+ QRegExp legalChars(QLatin1String("[a-zA-Z0-9_\\.]"));
+
+ for (int i = 0; i < packageName.length(); ++i) {
+ if (!legalChars.exactMatch(packageName.mid(i, 1)))
+ packageName[i] = QLatin1Char('_');
+ }
+
+ static QStringList keywords;
+ if (keywords.isEmpty()) {
+ keywords << QLatin1String("abstract") << QLatin1String("continue") << QLatin1String("for")
+ << QLatin1String("new") << QLatin1String("switch") << QLatin1String("assert")
+ << QLatin1String("default") << QLatin1String("if") << QLatin1String("package")
+ << QLatin1String("synchronized") << QLatin1String("boolean") << QLatin1String("do")
+ << QLatin1String("goto") << QLatin1String("private") << QLatin1String("this")
+ << QLatin1String("break") << QLatin1String("double") << QLatin1String("implements")
+ << QLatin1String("protected") << QLatin1String("throw") << QLatin1String("byte")
+ << QLatin1String("else") << QLatin1String("import") << QLatin1String("public")
+ << QLatin1String("throws") << QLatin1String("case") << QLatin1String("enum")
+ << QLatin1String("instanceof") << QLatin1String("return") << QLatin1String("transient")
+ << QLatin1String("catch") << QLatin1String("extends") << QLatin1String("int")
+ << QLatin1String("short") << QLatin1String("try") << QLatin1String("char")
+ << QLatin1String("final") << QLatin1String("interface") << QLatin1String("static")
+ << QLatin1String("void") << QLatin1String("class") << QLatin1String("finally")
+ << QLatin1String("long") << QLatin1String("strictfp") << QLatin1String("volatile")
+ << QLatin1String("const") << QLatin1String("float") << QLatin1String("native")
+ << QLatin1String("super") << QLatin1String("while");
+ }
+
+ // No keywords
+ int index = -1;
+ while (index < packageName.length()) {
+ int next = packageName.indexOf(QLatin1Char('.'), index + 1);
+ if (next == -1)
+ next = packageName.length();
+ QString word = packageName.mid(index + 1, next - index - 1);
+ if (!word.isEmpty()) {
+ QChar c = word[0];
+ if ((c >= QChar(QLatin1Char('0')) && c<= QChar(QLatin1Char('9')))
+ || c == QLatin1Char('_')) {
+ packageName.insert(index + 1, QLatin1Char('a'));
+ index = next + 1;
+ continue;
+ }
+ }
+ if (keywords.contains(word)) {
+ packageName.insert(next, QLatin1String("_"));
+ index = next + 1;
+ } else {
+ index = next;
+ }
+ }
+
+ return packageName;
+}
+
+QString detectLatestAndroidPlatform(const QString &sdkPath)
+{
+ QDir dir(sdkPath + QLatin1String("/platforms"));
+ if (!dir.exists()) {
+ fprintf(stderr, "Directory %s does not exist\n", qPrintable(dir.absolutePath()));
+ return QString();
+ }
+
+ QFileInfoList fileInfos = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ if (fileInfos.isEmpty()) {
+ fprintf(stderr, "No platforms found in %s", qPrintable(dir.absolutePath()));
+ return QString();
+ }
+
+ std::sort(fileInfos.begin(), fileInfos.end(), quasiLexicographicalReverseLessThan);
+
+ QFileInfo latestPlatform = fileInfos.first();
+ return latestPlatform.baseName();
+}
+
+QString packageNameFromAndroidManifest(const QString &androidManifestPath)
+{
+ QFile androidManifestXml(androidManifestPath);
+ if (androidManifestXml.open(QIODevice::ReadOnly)) {
+ QXmlStreamReader reader(&androidManifestXml);
+ while (!reader.atEnd()) {
+ reader.readNext();
+ if (reader.isStartElement() && reader.name() == QLatin1String("manifest"))
+ return cleanPackageName(
+ reader.attributes().value(QLatin1String("package")).toString());
+ }
+ }
+ return QString();
+}
+
+bool readInputFile(Options *options)
+{
+ QFile file(options->inputFileName);
+ if (!file.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Cannot read from input file: %s\n", qPrintable(options->inputFileName));
+ return false;
+ }
+
+ QJsonDocument jsonDocument = QJsonDocument::fromJson(file.readAll());
+ if (jsonDocument.isNull()) {
+ fprintf(stderr, "Invalid json file: %s\n", qPrintable(options->inputFileName));
+ return false;
+ }
+
+ QJsonObject jsonObject = jsonDocument.object();
+
+ {
+ QJsonValue sdkPath = jsonObject.value(QLatin1String("sdk"));
+ if (sdkPath.isUndefined()) {
+ fprintf(stderr, "No SDK path in json file %s\n", qPrintable(options->inputFileName));
+ return false;
+ }
+
+ options->sdkPath = sdkPath.toString();
+
+ if (options->androidPlatform.isEmpty()) {
+ options->androidPlatform = detectLatestAndroidPlatform(options->sdkPath);
+ if (options->androidPlatform.isEmpty())
+ return false;
+ } else {
+ if (!QDir(options->sdkPath + QLatin1String("/platforms/") + options->androidPlatform).exists()) {
+ fprintf(stderr, "Warning: Android platform '%s' does not exist in SDK.\n",
+ qPrintable(options->androidPlatform));
+ }
+ }
+ }
+
+ {
+
+ const QJsonValue value = jsonObject.value(QStringLiteral("sdkBuildToolsRevision"));
+ if (!value.isUndefined())
+ options->sdkBuildToolsVersion = value.toString();
+ }
+
+ {
+ const QJsonValue qtInstallDirectory = jsonObject.value(QStringLiteral("qt"));
+ if (qtInstallDirectory.isUndefined()) {
+ fprintf(stderr, "No Qt directory in json file %s\n", qPrintable(options->inputFileName));
+ return false;
+ }
+ options->qtInstallDirectory = qtInstallDirectory.toString();
+ }
+
+ {
+ const QJsonValue androidSourcesDirectory = jsonObject.value(QStringLiteral("android-package-source-directory"));
+ if (!androidSourcesDirectory.isUndefined())
+ options->androidSourceDirectory = androidSourcesDirectory.toString();
+ }
+
+ {
+ const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary"));
+ if (applicationBinary.isUndefined()) {
+ fprintf(stderr, "No application binary defined in json file.\n");
+ return false;
+ }
+ options->applicationBinary = applicationBinary.toString();
+
+ if (!QFile::exists(options->applicationBinary)) {
+ fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary));
+ return false;
+ }
+ }
+
+ {
+ const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies"));
+ if (!deploymentDependencies.isUndefined()) {
+ QString deploymentDependenciesString = deploymentDependencies.toString();
+ const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(','));
+ for (const QStringRef &dependency : dependencies) {
+ QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency;
+ if (QFileInfo(path).isDir()) {
+ QDirIterator iterator(path, QDirIterator::Subdirectories);
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (iterator.fileInfo().isFile()) {
+ QString subPath = iterator.filePath();
+ options->qtDependencies.append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1),
+ subPath));
+ }
+ }
+ } else {
+ options->qtDependencies.append(QtDependency(dependency.toString(), path));
+ }
+ }
+ }
+ }
+
+
+ {
+ const QJsonValue targetArchitecture = jsonObject.value(QStringLiteral("target-architecture"));
+ if (targetArchitecture.isUndefined()) {
+ fprintf(stderr, "No target architecture defined in json file.\n");
+ return false;
+ }
+ options->architecture = targetArchitecture.toString();
+ }
+
+ {
+ const QJsonValue ndk = jsonObject.value(QStringLiteral("ndk"));
+ if (ndk.isUndefined()) {
+ fprintf(stderr, "No NDK path defined in json file.\n");
+ return false;
+ }
+ options->ndkPath = ndk.toString();
+ }
+
+ {
+ const QJsonValue toolchainPrefix = jsonObject.value(QStringLiteral("toolchain-prefix"));
+ if (toolchainPrefix.isUndefined()) {
+ fprintf(stderr, "No toolchain prefix defined in json file.\n");
+ return false;
+ }
+ options->toolchainPrefix = toolchainPrefix.toString();
+ }
+
+ {
+ const QJsonValue toolPrefix = jsonObject.value(QStringLiteral("tool-prefix"));
+ if (toolPrefix.isUndefined()) {
+ fprintf(stderr, "Warning: No tool prefix defined in json file.\n");
+ options->toolPrefix = options->toolchainPrefix;
+ } else {
+ options->toolPrefix = toolPrefix.toString();
+ }
+ }
+
+ {
+ const QJsonValue toolchainVersion = jsonObject.value(QStringLiteral("toolchain-version"));
+ if (toolchainVersion.isUndefined()) {
+ fprintf(stderr, "No toolchain version defined in json file.\n");
+ return false;
+ }
+ options->toolchainVersion = toolchainVersion.toString();
+ }
+
+ {
+ const QJsonValue ndkHost = jsonObject.value(QStringLiteral("ndk-host"));
+ if (ndkHost.isUndefined()) {
+ fprintf(stderr, "No NDK host defined in json file.\n");
+ return false;
+ }
+ options->ndkHost = ndkHost.toString();
+ }
+
+ options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml"));
+ if (options->packageName.isEmpty())
+ options->packageName = cleanPackageName(QString::fromLatin1("org.qtproject.example.%1").arg(QFileInfo(options->applicationBinary).baseName().mid(sizeof("lib") - 1)));
+
+ {
+ const QJsonValue extraLibs = jsonObject.value(QStringLiteral("android-extra-libs"));
+ if (!extraLibs.isUndefined())
+ options->extraLibs = extraLibs.toString().split(QLatin1Char(','), QString::SkipEmptyParts);
+ }
+
+ {
+ const QJsonValue extraPlugins = jsonObject.value(QStringLiteral("android-extra-plugins"));
+ if (!extraPlugins.isUndefined())
+ options->extraPlugins = extraPlugins.toString().split(QLatin1Char(','));
+ }
+
+ {
+ const QJsonValue stdcppPath = jsonObject.value(QStringLiteral("stdcpp-path"));
+ if (!stdcppPath.isUndefined()) {
+ options->stdCppPath = stdcppPath.toString();
+ auto name = QFileInfo(options->stdCppPath).baseName();
+ if (!name.startsWith(QLatin1String("lib"))) {
+ fprintf(stderr, "Invalid STD C++ library name.\n");
+ return false;
+ }
+ options->stdCppName = name.mid(3);
+ }
+ }
+
+ {
+ const QJsonValue qmlRootPath = jsonObject.value(QStringLiteral("qml-root-path"));
+ if (!qmlRootPath.isUndefined())
+ options->rootPath = qmlRootPath.toString();
+ }
+
+ {
+ const QJsonValue qmlImportPaths = jsonObject.value(QStringLiteral("qml-import-paths"));
+ if (!qmlImportPaths.isUndefined())
+ options->qmlImportPaths = qmlImportPaths.toString().split(QLatin1Char(','));
+ }
+ return true;
+}
+
+bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bool verbose, bool forceOverwrite = false)
+{
+ const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
+ for (const QFileInfo &entry : entries) {
+ if (entry.isDir()) {
+ QDir dir(entry.absoluteFilePath());
+ if (!destinationDirectory.mkpath(dir.dirName())) {
+ fprintf(stderr, "Cannot make directory %s in %s\n", qPrintable(dir.dirName()), qPrintable(destinationDirectory.path()));
+ return false;
+ }
+
+ if (!copyFiles(dir, QDir(destinationDirectory.path() + QLatin1String("/") + dir.dirName()), verbose, forceOverwrite))
+ return false;
+ } else {
+ QString destination = destinationDirectory.absoluteFilePath(entry.fileName());
+ if (!copyFileIfNewer(entry.absoluteFilePath(), destination, verbose, forceOverwrite))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void cleanTopFolders(const Options &options, const QDir &srcDir, const QString &dstDir)
+{
+ const auto dirs = srcDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs);
+ for (const QFileInfo &dir : dirs) {
+ if (dir.fileName() != QLatin1String("libs"))
+ deleteMissingFiles(options, dir.absoluteFilePath(), dstDir + dir.fileName());
+ }
+}
+
+void cleanAndroidFiles(const Options &options)
+{
+ if (!options.androidSourceDirectory.isEmpty())
+ cleanTopFolders(options, options.androidSourceDirectory, options.outputDirectory);
+
+ cleanTopFolders(options, options.qtInstallDirectory + QLatin1String("/src/android/templates"), options.outputDirectory);
+}
+
+bool copyAndroidTemplate(const Options &options, const QString &androidTemplate, const QString &outDirPrefix = QString())
+{
+ QDir sourceDirectory(options.qtInstallDirectory + androidTemplate);
+ if (!sourceDirectory.exists()) {
+ fprintf(stderr, "Cannot find template directory %s\n", qPrintable(sourceDirectory.absolutePath()));
+ return false;
+ }
+
+ QString outDir = options.outputDirectory + outDirPrefix;
+
+ if (!QDir::current().mkpath(outDir)) {
+ fprintf(stderr, "Cannot create output directory %s\n", qPrintable(options.outputDirectory));
+ return false;
+ }
+
+ return copyFiles(sourceDirectory, QDir(outDir), options.verbose);
+}
+
+bool copyGradleTemplate(const Options &options)
+{
+ QDir sourceDirectory(options.qtInstallDirectory + QLatin1String("/src/3rdparty/gradle"));
+ if (!sourceDirectory.exists()) {
+ fprintf(stderr, "Cannot find template directory %s\n", qPrintable(sourceDirectory.absolutePath()));
+ return false;
+ }
+
+ QString outDir(options.outputDirectory);
+ if (!QDir::current().mkpath(outDir)) {
+ fprintf(stderr, "Cannot create output directory %s\n", qPrintable(options.outputDirectory));
+ return false;
+ }
+
+ return copyFiles(sourceDirectory, QDir(outDir), options.verbose);
+}
+
+bool copyAndroidTemplate(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Copying Android package template.\n");
+
+ if (options.gradle && !copyGradleTemplate(options))
+ return false;
+
+ if (!copyAndroidTemplate(options, QLatin1String("/src/android/templates")))
+ return false;
+
+ if (options.gradle)
+ return true;
+
+ return copyAndroidTemplate(options, QLatin1String("/src/android/java"));
+}
+
+bool copyAndroidSources(const Options &options)
+{
+ if (options.androidSourceDirectory.isEmpty())
+ return true;
+
+ if (options.verbose)
+ fprintf(stdout, "Copying Android sources from project.\n");
+
+ QDir sourceDirectory(options.androidSourceDirectory);
+ if (!sourceDirectory.exists()) {
+ fprintf(stderr, "Cannot find android sources in %s", qPrintable(options.androidSourceDirectory));
+ return false;
+ }
+
+ return copyFiles(sourceDirectory, QDir(options.outputDirectory), options.verbose, true);
+}
+
+bool copyAndroidExtraLibs(const Options &options)
+{
+ if (options.extraLibs.isEmpty())
+ return true;
+
+ if (options.verbose)
+ fprintf(stdout, "Copying %d external libraries to package.\n", options.extraLibs.size());
+
+ for (const QString &extraLib : options.extraLibs) {
+ QFileInfo extraLibInfo(extraLib);
+ if (!extraLibInfo.exists()) {
+ fprintf(stderr, "External library %s does not exist!\n", qPrintable(extraLib));
+ return false;
+ }
+
+ if (!extraLibInfo.fileName().startsWith(QLatin1String("lib")) || extraLibInfo.suffix() != QLatin1String("so")) {
+ fprintf(stderr, "The file name of external library %s must begin with \"lib\" and end with the suffix \".so\".\n",
+ qPrintable(extraLib));
+ return false;
+ }
+
+ QString destinationFile(options.outputDirectory
+ + QLatin1String("/libs/")
+ + options.architecture
+ + QLatin1Char('/')
+ + extraLibInfo.fileName());
+
+ if (!copyFileIfNewer(extraLib, destinationFile, options.verbose))
+ return false;
+ }
+
+ return true;
+}
+
+QStringList allFilesInside(const QDir& current, const QDir& rootDir)
+{
+ QStringList result;
+ const auto dirs = current.entryList(QDir::Dirs|QDir::NoDotAndDotDot);
+ const auto files = current.entryList(QDir::Files);
+ result.reserve(dirs.size() + files.size());
+ for (const QString &dir : dirs) {
+ result += allFilesInside(QDir(current.filePath(dir)), rootDir);
+ }
+ for (const QString &file : files) {
+ result += rootDir.relativeFilePath(current.filePath(file));
+ }
+ return result;
+}
+
+bool copyAndroidExtraResources(const Options &options)
+{
+ if (options.extraPlugins.isEmpty())
+ return true;
+
+ if (options.verbose)
+ fprintf(stdout, "Copying %d external resources to package.\n", options.extraPlugins.size());
+
+ for (const QString &extraResource : options.extraPlugins) {
+ QFileInfo extraResourceInfo(extraResource);
+ if (!extraResourceInfo.exists() || !extraResourceInfo.isDir()) {
+ fprintf(stderr, "External resource %s does not exist or not a correct directory!\n", qPrintable(extraResource));
+ return false;
+ }
+
+ QDir resourceDir(extraResource);
+ QString assetsDir = options.outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/');
+ QString libsDir = options.outputDirectory + QStringLiteral("/libs/") + options.architecture + QLatin1Char('/');
+
+ const QStringList files = allFilesInside(resourceDir, resourceDir);
+ for (const QString &resourceFile : files) {
+ QString originFile(resourceDir.filePath(resourceFile));
+ QString destinationFile;
+ if (!resourceFile.endsWith(QLatin1String(".so"))) {
+ destinationFile = assetsDir + resourceFile;
+ } else {
+ destinationFile = libsDir + QStringLiteral("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_'));
+ }
+
+ if (!copyFileIfNewer(originFile, destinationFile, options.verbose))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool updateFile(const QString &fileName, const QHash<QString, QString> &replacements)
+{
+ QFile inputFile(fileName);
+ if (!inputFile.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(fileName));
+ return false;
+ }
+
+ // All the files we are doing substitutes in are quite small. If this
+ // ever changes, this code should be updated to be more conservative.
+ QByteArray contents = inputFile.readAll();
+
+ bool hasReplacements = false;
+ QHash<QString, QString>::const_iterator it;
+ for (it = replacements.constBegin(); it != replacements.constEnd(); ++it) {
+ if (it.key() == it.value())
+ continue; // Nothing to actually replace
+
+ forever {
+ int index = contents.indexOf(it.key().toUtf8());
+ if (index >= 0) {
+ contents.replace(index, it.key().length(), it.value().toUtf8());
+ hasReplacements = true;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (hasReplacements) {
+ inputFile.close();
+
+ if (!inputFile.open(QIODevice::WriteOnly)) {
+ fprintf(stderr, "Cannot open %s for writing.\n", qPrintable(fileName));
+ return false;
+ }
+
+ inputFile.write(contents);
+ }
+
+ return true;
+
+}
+
+bool updateLibsXml(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, " -- res/values/libs.xml\n");
+
+ QString fileName = options.outputDirectory + QLatin1String("/res/values/libs.xml");
+ if (!QFile::exists(fileName)) {
+ fprintf(stderr, "Cannot find %s in prepared packaged. This file is required.\n", qPrintable(fileName));
+ return false;
+ }
+
+ QString libsPath = QLatin1String("libs/") + options.architecture + QLatin1Char('/');
+
+ QString qtLibs = QLatin1String("<item>") + options.stdCppName + QLatin1String("</item>\n");
+ QString bundledInLibs;
+ QString bundledInAssets;
+ for (const Options::BundledFile &bundledFile : options.bundledFiles) {
+ if (bundledFile.second.startsWith(QLatin1String("lib/"))) {
+ QString s = bundledFile.second.mid(sizeof("lib/lib") - 1);
+ s.chop(sizeof(".so") - 1);
+ qtLibs += QString::fromLatin1("<item>%1</item>\n").arg(s);
+ } else if (bundledFile.first.startsWith(libsPath)) {
+ QString s = bundledFile.first.mid(libsPath.length());
+ bundledInLibs += QString::fromLatin1("<item>%1:%2</item>\n")
+ .arg(s).arg(bundledFile.second);
+ } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) {
+ QString s = bundledFile.first.mid(sizeof("assets/") - 1);
+ bundledInAssets += QString::fromLatin1("<item>%1:%2</item>\n")
+ .arg(s).arg(bundledFile.second);
+ }
+ }
+
+ if (!options.extraPlugins.isEmpty()) {
+ for (const QString &extraRes : options.extraPlugins) {
+ QDir resourceDir(extraRes);
+ const QStringList files = allFilesInside(resourceDir, resourceDir);
+ for (const QString &file : files) {
+ QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file;
+ if (!file.endsWith(QLatin1String(".so"))) {
+ bundledInAssets += QStringLiteral("<item>%1:%1</item>\n")
+ .arg(destinationPath);
+ } else {
+ bundledInLibs += QStringLiteral("<item>lib%1:%2</item>\n")
+ .arg(QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_')))
+ .arg(destinationPath);
+ }
+ }
+ }
+ }
+
+ QHash<QString, QString> replacements;
+ replacements[QLatin1String("<!-- %%INSERT_QT_LIBS%% -->")] = qtLibs;
+
+ if (options.deploymentMechanism == Options::Bundled) {
+ replacements[QLatin1String("<!-- %%INSERT_BUNDLED_IN_LIB%% -->")] = bundledInLibs;
+ replacements[QLatin1String("<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->")] = bundledInAssets;
+ }
+
+ QString extraLibs;
+ if (!options.extraLibs.isEmpty()) {
+ for (const QString extraLib : options.extraLibs) {
+ QFileInfo extraLibInfo(extraLib);
+ QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1);
+ name.chop(sizeof(".so") - 1);
+
+ extraLibs += QLatin1String("<item>") + name + QLatin1String("</item>\n");
+ }
+ }
+ replacements[QLatin1String("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs;
+
+ if (!updateFile(fileName, replacements))
+ return false;
+
+ return true;
+}
+
+bool updateStringsXml(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, " -- res/values/strings.xml\n");
+
+ QHash<QString, QString> replacements;
+ replacements[QStringLiteral("<!-- %%INSERT_APP_NAME%% -->")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
+
+ QString fileName = options.outputDirectory + QLatin1String("/res/values/strings.xml");
+ if (!QFile::exists(fileName)) {
+ if (options.verbose)
+ fprintf(stdout, " -- Create strings.xml since it's missing.\n");
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ fprintf(stderr, "Can't open %s for writing.\n", qPrintable(fileName));
+ return false;
+ }
+ file.write(QByteArray("<?xml version='1.0' encoding='utf-8'?><resources><string name=\"app_name\">")
+ .append(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1).toLatin1())
+ .append("</string></resources>\n"));
+ return true;
+ }
+
+ if (!updateFile(fileName, replacements))
+ return false;
+
+ if (options.gradle)
+ return true;
+
+ // ant can't (easily) build multiple res folders,
+ // so we need to replace the "<!-- %%INSERT_STRINGS -->" placeholder
+ // from the main res folder
+ QFile stringsXml(fileName);
+ if (!stringsXml.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(fileName));
+ return false;
+ }
+
+ QXmlStreamReader reader(&stringsXml);
+ while (!reader.atEnd()) {
+ reader.readNext();
+ if (reader.isStartElement() &&
+ reader.name() == QLatin1String("string") &&
+ reader.attributes().hasAttribute(QLatin1String("name")) &&
+ reader.attributes().value(QLatin1String("name")) == QLatin1String("app_name")) {
+ return true;
+ }
+ }
+
+ replacements.clear();
+ replacements[QStringLiteral("<!-- %%INSERT_STRINGS -->")] = QString::fromLatin1("<string name=\"app_name\">%1</string>\n")
+ .arg(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1));
+
+ if (!updateFile(fileName, replacements))
+ return false;
+
+ return true;
+}
+
+bool updateAndroidManifest(Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, " -- AndroidManifest.xml \n");
+
+ QStringList localLibs = options.localLibs;
+
+ // If .pro file overrides dependency detection, we need to see which platform plugin they picked
+ if (localLibs.isEmpty()) {
+ QString plugin;
+ for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) {
+ if (qtDependency.relativePath.endsWith(QLatin1String("libqtforandroid.so"))
+ || qtDependency.relativePath.endsWith(QLatin1String("libqtforandroidGL.so"))) {
+ if (!plugin.isEmpty() && plugin != qtDependency.relativePath) {
+ fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n");
+ return false;
+ }
+
+ plugin = qtDependency.relativePath;
+ }
+ }
+
+ if (plugin.isEmpty()) {
+ fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n");
+ return false;
+ }
+
+ localLibs.append(plugin);
+ if (options.verbose)
+ fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin));
+ }
+
+ bool usesGL = false;
+ for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) {
+ if (qtDependency.relativePath.endsWith(QLatin1String("libQt5OpenGL.so"))
+ || qtDependency.relativePath.endsWith(QLatin1String("libQt5Quick.so"))) {
+ usesGL = true;
+ break;
+ }
+ }
+
+ options.localJars.removeDuplicates();
+ options.initClasses.removeDuplicates();
+
+ QHash<QString, QString> replacements;
+ replacements[QLatin1String("-- %%INSERT_APP_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
+ replacements[QLatin1String("-- %%INSERT_APP_LIB_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
+ replacements[QLatin1String("-- %%INSERT_LOCAL_LIBS%% --")] = localLibs.join(QLatin1Char(':'));
+ replacements[QLatin1String("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':'));
+ replacements[QLatin1String("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':'));
+ replacements[QLatin1String("package=\"org.qtproject.example\"")] = QString::fromLatin1("package=\"%1\"").arg(options.packageName);
+ replacements[QLatin1String("-- %%BUNDLE_LOCAL_QT_LIBS%% --")]
+ = (options.deploymentMechanism == Options::Bundled) ? QString::fromLatin1("1") : QString::fromLatin1("0");
+ replacements[QLatin1String("-- %%USE_LOCAL_QT_LIBS%% --")]
+ = (options.deploymentMechanism != Options::Ministro) ? QString::fromLatin1("1") : QString::fromLatin1("0");
+
+ QString permissions;
+ for (const QString &permission : qAsConst(options.permissions))
+ permissions += QString::fromLatin1(" <uses-permission android:name=\"%1\" />\n").arg(permission);
+ replacements[QLatin1String("<!-- %%INSERT_PERMISSIONS -->")] = permissions;
+
+ QString features;
+ for (const QString &feature : qAsConst(options.features))
+ features += QStringLiteral(" <uses-feature android:name=\"%1\" android:required=\"false\" />\n").arg(feature);
+ if (usesGL)
+ features += QStringLiteral(" <uses-feature android:glEsVersion=\"0x00020000\" android:required=\"true\" />");
+
+ replacements[QLatin1String("<!-- %%INSERT_FEATURES -->")] = features;
+
+ QString androidManifestPath = options.outputDirectory + QLatin1String("/AndroidManifest.xml");
+ if (!updateFile(androidManifestPath, replacements))
+ return false;
+
+ // read the package, min & target sdk API levels from manifest file.
+ bool checkOldAndroidLabelString = false;
+ QFile androidManifestXml(androidManifestPath);
+ if (androidManifestXml.exists()) {
+ if (!androidManifestXml.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(androidManifestPath));
+ return false;
+ }
+
+ QXmlStreamReader reader(&androidManifestXml);
+ while (!reader.atEnd()) {
+ reader.readNext();
+
+ if (reader.isStartElement()) {
+ if (reader.name() == QLatin1String("manifest")) {
+ if (!reader.attributes().hasAttribute(QLatin1String("package"))) {
+ fprintf(stderr, "Invalid android manifest file: %s\n", qPrintable(androidManifestPath));
+ return false;
+ }
+ options.packageName = reader.attributes().value(QLatin1String("package")).toString();
+ } else if (reader.name() == QLatin1String("uses-sdk")) {
+ if (reader.attributes().hasAttribute(QLatin1String("android:minSdkVersion")))
+ if (reader.attributes().value(QLatin1String("android:minSdkVersion")).toInt() < 16) {
+ fprintf(stderr, "Invalid minSdkVersion version, minSdkVersion must be >= 16\n");
+ return false;
+ }
+ } else if ((reader.name() == QLatin1String("application") ||
+ reader.name() == QLatin1String("activity")) &&
+ reader.attributes().hasAttribute(QLatin1String("android:label")) &&
+ reader.attributes().value(QLatin1String("android:label")) == QLatin1String("@string/app_name")) {
+ checkOldAndroidLabelString = true;
+ }
+ }
+ }
+
+ if (reader.hasError()) {
+ fprintf(stderr, "Error in %s: %s\n", qPrintable(androidManifestPath), qPrintable(reader.errorString()));
+ return false;
+ }
+ } else {
+ fprintf(stderr, "No android manifest file");
+ return false;
+ }
+
+ if (checkOldAndroidLabelString)
+ updateStringsXml(options);
+
+ return true;
+}
+
+bool updateAndroidFiles(Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Updating Android package files with project settings.\n");
+
+ if (!updateLibsXml(options))
+ return false;
+
+ if (!updateAndroidManifest(options))
+ return false;
+
+ return true;
+}
+
+QList<QtDependency> findFilesRecursively(const Options &options, const QFileInfo &info, const QString &rootPath)
+{
+ if (!info.exists())
+ return QList<QtDependency>();
+
+ if (info.isDir()) {
+ QList<QtDependency> ret;
+
+ QDir dir(info.filePath());
+ const QStringList entries = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
+
+ for (const QString &entry : entries) {
+ QString s = info.absoluteFilePath() + QLatin1Char('/') + entry;
+ ret += findFilesRecursively(options, s, rootPath);
+ }
+
+ return ret;
+ } else {
+ return QList<QtDependency>() << QtDependency(info.absoluteFilePath().mid(rootPath.length()), info.absoluteFilePath());
+ }
+}
+
+QList<QtDependency> findFilesRecursively(const Options &options, const QString &fileName)
+{
+ QFileInfo info(options.qtInstallDirectory + QLatin1Char('/') + fileName);
+ return findFilesRecursively(options, info, options.qtInstallDirectory + QLatin1Char('/'));
+}
+
+bool readAndroidDependencyXml(Options *options,
+ const QString &moduleName,
+ QSet<QString> *usedDependencies,
+ QSet<QString> *remainingDependencies)
+{
+ QString androidDependencyName = options->qtInstallDirectory + QString::fromLatin1("/lib/%1-android-dependencies.xml").arg(moduleName);
+
+ QFile androidDependencyFile(androidDependencyName);
+ if (androidDependencyFile.exists()) {
+ if (options->verbose)
+ fprintf(stdout, "Reading Android dependencies for %s\n", qPrintable(moduleName));
+
+ if (!androidDependencyFile.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(androidDependencyName));
+ return false;
+ }
+
+ QXmlStreamReader reader(&androidDependencyFile);
+ while (!reader.atEnd()) {
+ reader.readNext();
+
+ if (reader.isStartElement()) {
+ if (reader.name() == QLatin1String("bundled")) {
+ if (!reader.attributes().hasAttribute(QLatin1String("file"))) {
+ fprintf(stderr, "Invalid android dependency file: %s\n", qPrintable(androidDependencyName));
+ return false;
+ }
+
+ QString file = reader.attributes().value(QLatin1String("file")).toString();
+
+ // Special case, since this is handled by qmlimportscanner instead
+ if (!options->rootPath.isEmpty() && (file == QLatin1String("qml") || file == QLatin1String("qml/")))
+ continue;
+
+ const QList<QtDependency> fileNames = findFilesRecursively(*options, file);
+ for (const QtDependency &fileName : fileNames) {
+ if (usedDependencies->contains(fileName.absolutePath))
+ continue;
+
+ usedDependencies->insert(fileName.absolutePath);
+
+ if (options->verbose)
+ fprintf(stdout, "Appending dependency from xml: %s\n", qPrintable(fileName.relativePath));
+
+ options->qtDependencies.append(fileName);
+ }
+ } else if (reader.name() == QLatin1String("jar")) {
+ int bundling = reader.attributes().value(QLatin1String("bundling")).toInt();
+ QString fileName = reader.attributes().value(QLatin1String("file")).toString();
+ if (bundling == (options->deploymentMechanism == Options::Bundled)) {
+ QtDependency dependency(fileName, options->qtInstallDirectory + QLatin1Char('/') + fileName);
+ if (!usedDependencies->contains(dependency.absolutePath)) {
+ options->qtDependencies.append(dependency);
+ usedDependencies->insert(dependency.absolutePath);
+ }
+ }
+
+ if (!fileName.isEmpty())
+ options->localJars.append(fileName);
+
+ if (reader.attributes().hasAttribute(QLatin1String("initClass"))) {
+ options->initClasses.append(reader.attributes().value(QLatin1String("initClass")).toString());
+ }
+ } else if (reader.name() == QLatin1String("lib")) {
+ QString fileName = reader.attributes().value(QLatin1String("file")).toString();
+ if (reader.attributes().hasAttribute(QLatin1String("replaces"))) {
+ QString replaces = reader.attributes().value(QLatin1String("replaces")).toString();
+ for (int i=0; i<options->localLibs.size(); ++i) {
+ if (options->localLibs.at(i) == replaces) {
+ options->localLibs[i] = fileName;
+ break;
+ }
+ }
+ } else if (!fileName.isEmpty()) {
+ options->localLibs.append(fileName);
+ }
+ if (fileName.endsWith(QLatin1String(".so"))) {
+ remainingDependencies->insert(fileName);
+ }
+ } else if (reader.name() == QLatin1String("permission")) {
+ QString name = reader.attributes().value(QLatin1String("name")).toString();
+ options->permissions.append(name);
+ } else if (reader.name() == QLatin1String("feature")) {
+ QString name = reader.attributes().value(QLatin1String("name")).toString();
+ options->features.append(name);
+ }
+ }
+ }
+
+ if (reader.hasError()) {
+ fprintf(stderr, "Error in %s: %s\n", qPrintable(androidDependencyName), qPrintable(reader.errorString()));
+ return false;
+ }
+ } else if (options->verbose) {
+ fprintf(stdout, "No android dependencies for %s\n", qPrintable(moduleName));
+ }
+
+ return true;
+}
+
+QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
+{
+ QString readElf = options.ndkPath
+ + QLatin1String("/toolchains/")
+ + options.toolchainPrefix
+ + QLatin1Char('-')
+ + options.toolchainVersion
+ + QLatin1String("/prebuilt/")
+ + options.ndkHost
+ + QLatin1String("/bin/")
+ + options.toolPrefix
+ + QLatin1String("-readelf");
+#if defined(Q_OS_WIN32)
+ readElf += QLatin1String(".exe");
+#endif
+
+ if (!QFile::exists(readElf)) {
+ fprintf(stderr, "Command does not exist: %s\n", qPrintable(readElf));
+ return QStringList();
+ }
+
+ readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf)).arg(shellQuote(fileName));
+
+ FILE *readElfCommand = openProcess(readElf);
+ if (readElfCommand == 0) {
+ fprintf(stderr, "Cannot execute command %s", qPrintable(readElf));
+ return QStringList();
+ }
+
+ QStringList ret;
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), readElfCommand) != 0) {
+ QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
+ if (line.contains("(NEEDED)") && line.contains("Shared library:") ) {
+ const int pos = line.lastIndexOf('[') + 1;
+ QString libraryName = QLatin1String("lib/") + QString::fromLatin1(line.mid(pos, line.length() - pos - 2));
+ if (QFile::exists(options.qtInstallDirectory + QLatin1Char('/') + libraryName)) {
+ ret += libraryName;
+ }
+
+ }
+ }
+
+ pclose(readElfCommand);
+
+ return ret;
+}
+
+bool readDependenciesFromElf(Options *options,
+ const QString &fileName,
+ QSet<QString> *usedDependencies,
+ QSet<QString> *remainingDependencies)
+{
+ // Get dependencies on libraries in $QTDIR/lib
+ const QStringList dependencies = getQtLibsFromElf(*options, fileName);
+
+ if (options->verbose) {
+ fprintf(stdout, "Reading dependencies from %s\n", qPrintable(fileName));
+ for (const QString &dep : dependencies)
+ fprintf(stdout, " %s\n", qPrintable(dep));
+ }
+ // Recursively add dependencies from ELF and supplementary XML information
+ QList<QString> dependenciesToCheck;
+ for (const QString &dependency : dependencies) {
+ if (usedDependencies->contains(dependency))
+ continue;
+
+ QString absoluteDependencyPath(options->qtInstallDirectory + QLatin1Char('/') + dependency);
+ usedDependencies->insert(dependency);
+ if (!readDependenciesFromElf(options,
+ absoluteDependencyPath,
+ usedDependencies,
+ remainingDependencies)) {
+ return false;
+ }
+
+ options->qtDependencies.append(QtDependency(dependency, absoluteDependencyPath));
+ if (options->verbose)
+ fprintf(stdout, "Appending dependency: %s\n", qPrintable(dependency));
+ dependenciesToCheck.append(dependency);
+ }
+
+ for (const QString &dependency : qAsConst(dependenciesToCheck)) {
+ QString qtBaseName = dependency.mid(sizeof("lib/lib") - 1);
+ qtBaseName = qtBaseName.left(qtBaseName.size() - (sizeof(".so") - 1));
+ if (!readAndroidDependencyXml(options, qtBaseName, usedDependencies, remainingDependencies)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool goodToCopy(const Options *options, const QString &file, QStringList *unmetDependencies);
+
+bool scanImports(Options *options, QSet<QString> *usedDependencies)
+{
+ if (options->verbose)
+ fprintf(stdout, "Scanning for QML imports.\n");
+
+ QString qmlImportScanner = options->qtInstallDirectory + QLatin1String("/bin/qmlimportscanner");
+#if defined(Q_OS_WIN32)
+ qmlImportScanner += QLatin1String(".exe");
+#endif
+
+ if (!QFile::exists(qmlImportScanner)) {
+ fprintf(stderr, "qmlimportscanner not found: %s\n", qPrintable(qmlImportScanner));
+ return true;
+ }
+
+ QString rootPath = options->rootPath;
+ if (rootPath.isEmpty())
+ rootPath = QFileInfo(options->inputFileName).absolutePath();
+ else
+ rootPath = QFileInfo(rootPath).absoluteFilePath();
+
+ if (!rootPath.endsWith(QLatin1Char('/')))
+ rootPath += QLatin1Char('/');
+
+ QStringList importPaths;
+ importPaths += shellQuote(options->qtInstallDirectory + QLatin1String("/qml"));
+ importPaths += rootPath;
+ for (const QString &qmlImportPath : qAsConst(options->qmlImportPaths))
+ importPaths += shellQuote(qmlImportPath);
+
+ qmlImportScanner += QString::fromLatin1(" -rootPath %1 -importPath %2")
+ .arg(shellQuote(rootPath))
+ .arg(importPaths.join(QLatin1Char(' ')));
+
+ FILE *qmlImportScannerCommand = popen(qmlImportScanner.toLocal8Bit().constData(), "r");
+ if (qmlImportScannerCommand == 0) {
+ fprintf(stderr, "Couldn't run qmlimportscanner.\n");
+ return false;
+ }
+
+ QByteArray output;
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand) != 0)
+ output += QByteArray(buffer, qstrlen(buffer));
+
+ QJsonDocument jsonDocument = QJsonDocument::fromJson(output);
+ if (jsonDocument.isNull()) {
+ fprintf(stderr, "Invalid json output from qmlimportscanner.\n");
+ return false;
+ }
+
+ QJsonArray jsonArray = jsonDocument.array();
+ for (int i=0; i<jsonArray.count(); ++i) {
+ QJsonValue value = jsonArray.at(i);
+ if (!value.isObject()) {
+ fprintf(stderr, "Invalid format of qmlimportscanner output.\n");
+ return false;
+ }
+
+ QJsonObject object = value.toObject();
+ QString path = object.value(QLatin1String("path")).toString();
+ if (path.isEmpty()) {
+ fprintf(stderr, "Warning: QML import could not be resolved in any of the import paths: %s\n",
+ qPrintable(object.value(QLatin1String("name")).toString()));
+ } else {
+ if (options->verbose)
+ fprintf(stdout, " -- Adding '%s' as QML dependency\n", path.toLocal8Bit().constData());
+
+ QFileInfo info(path);
+
+ // The qmlimportscanner sometimes outputs paths that do not exist.
+ if (!info.exists()) {
+ if (options->verbose)
+ fprintf(stdout, " -- Skipping because file does not exist.\n");
+ continue;
+ }
+
+ QString absolutePath = info.absolutePath();
+ if (!absolutePath.endsWith(QLatin1Char('/')))
+ absolutePath += QLatin1Char('/');
+
+ if (absolutePath.startsWith(rootPath)) {
+ if (options->verbose)
+ fprintf(stdout, " -- Skipping because file is in QML root path.\n");
+ continue;
+ }
+
+ QString importPathOfThisImport;
+ for (const QString &importPath : qAsConst(importPaths)) {
+#if defined(Q_OS_WIN32)
+ Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive;
+#else
+ Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive;
+#endif
+ QString cleanImportPath = QDir::cleanPath(importPath);
+ if (info.absoluteFilePath().startsWith(cleanImportPath, caseSensitivity)) {
+ importPathOfThisImport = importPath;
+ break;
+ }
+ }
+
+ if (importPathOfThisImport.isEmpty()) {
+ fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath()));
+ return false;
+ }
+
+ QDir dir(importPathOfThisImport);
+ importPathOfThisImport = dir.absolutePath() + QLatin1Char('/');
+
+ const QList<QtDependency> fileNames = findFilesRecursively(*options, info, importPathOfThisImport);
+ for (QtDependency fileName : fileNames) {
+ if (usedDependencies->contains(fileName.absolutePath))
+ continue;
+
+ usedDependencies->insert(fileName.absolutePath);
+
+ if (options->verbose)
+ fprintf(stdout, " -- Appending dependency found by qmlimportscanner: %s\n", qPrintable(fileName.absolutePath));
+
+ // Put all imports in default import path in assets
+ fileName.relativePath.prepend(QLatin1String("qml/"));
+ options->qtDependencies.append(fileName);
+
+ if (fileName.absolutePath.endsWith(QLatin1String(".so"))) {
+ QSet<QString> remainingDependencies;
+ if (!readDependenciesFromElf(options, fileName.absolutePath, usedDependencies, &remainingDependencies))
+ return false;
+
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool readDependencies(Options *options)
+{
+ if (options->verbose)
+ fprintf(stdout, "Detecting dependencies of application.\n");
+
+ // Override set in .pro file
+ if (!options->qtDependencies.isEmpty()) {
+ if (options->verbose)
+ fprintf(stdout, "\tDependencies explicitly overridden in .pro file. No detection needed.\n");
+ return true;
+ }
+
+ QSet<QString> usedDependencies;
+ QSet<QString> remainingDependencies;
+
+ // Add dependencies of application binary first
+ if (!readDependenciesFromElf(options, options->applicationBinary, &usedDependencies, &remainingDependencies))
+ return false;
+
+ // Jam in the dependencies of the platform plugin, since the application will crash without it
+ if (!readDependenciesFromElf(options, options->qtInstallDirectory + QLatin1String("/plugins/platforms/android/libqtforandroid.so"), &usedDependencies, &remainingDependencies))
+ return false;
+
+ QString qtDir = options->qtInstallDirectory + QLatin1Char('/');
+
+ while (!remainingDependencies.isEmpty()) {
+ QSet<QString>::iterator start = remainingDependencies.begin();
+ QString fileName = qtDir + *start;
+ remainingDependencies.erase(start);
+
+ QStringList unmetDependencies;
+ if (goodToCopy(options, fileName, &unmetDependencies)) {
+ bool ok = readDependenciesFromElf(options, fileName, &usedDependencies, &remainingDependencies);
+ if (!ok)
+ return false;
+ } else {
+ fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n",
+ qPrintable(fileName),
+ qPrintable(unmetDependencies.join(QLatin1Char(','))));
+ }
+ }
+
+ QStringList::iterator it = options->localLibs.begin();
+ while (it != options->localLibs.end()) {
+ QStringList unmetDependencies;
+ if (!goodToCopy(options, qtDir + *it, &unmetDependencies)) {
+ fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n",
+ qPrintable(*it),
+ qPrintable(unmetDependencies.join(QLatin1Char(','))));
+ it = options->localLibs.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ if (!options->rootPath.isEmpty() && !scanImports(options, &usedDependencies))
+ return false;
+
+ return true;
+}
+
+bool stripFile(const Options &options, const QString &fileName)
+{
+ QString strip = options.ndkPath
+ + QLatin1String("/toolchains/")
+ + options.toolchainPrefix
+ + QLatin1Char('-')
+ + options.toolchainVersion
+ + QLatin1String("/prebuilt/")
+ + options.ndkHost
+ + QLatin1String("/bin/")
+ + options.toolPrefix
+ + QLatin1String("-strip");
+#if defined(Q_OS_WIN32)
+ strip += QLatin1String(".exe");
+#endif
+
+ if (!QFile::exists(strip)) {
+ fprintf(stderr, "Command does not exist: %s\n", qPrintable(strip));
+ return false;
+ }
+
+ strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip)).arg(shellQuote(fileName));
+
+ FILE *stripCommand = openProcess(strip);
+ if (stripCommand == 0) {
+ fprintf(stderr, "Cannot execute command %s", qPrintable(strip));
+ return false;
+ }
+
+ pclose(stripCommand);
+
+ return true;
+}
+
+bool stripLibraries(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Stripping libraries to minimize size.\n");
+
+
+ QString libraryPath = options.outputDirectory
+ + QLatin1String("/libs/")
+ + options.architecture;
+ const QStringList libraries = QDir(libraryPath).entryList(QDir::Files);
+ for (const QString &library : libraries) {
+ if (library.endsWith(QLatin1String(".so"))) {
+ if (!stripFile(options, libraryPath + QLatin1Char('/') + library))
+ return false;
+ }
+ }
+
+
+ return true;
+}
+
+bool containsApplicationBinary(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Checking if application binary is in package.\n");
+
+ QFileInfo applicationBinary(options.applicationBinary);
+ QString destinationFileName = options.outputDirectory
+ + QLatin1String("/libs/")
+ + options.architecture
+ + QLatin1Char('/')
+ + applicationBinary.fileName();
+
+ if (!QFile::exists(destinationFileName)) {
+#if defined(Q_OS_WIN32)
+ QLatin1String makeTool("mingw32-make"); // Only Mingw host builds supported on Windows currently
+#else
+ QLatin1String makeTool("make");
+#endif
+
+ fprintf(stderr, "Application binary is not in output directory: %s. Please run '%s install INSTALL_ROOT=%s' first.\n",
+ qPrintable(destinationFileName),
+ qPrintable(makeTool),
+ qPrintable(options.outputDirectory));
+ return false;
+ }
+
+ return true;
+}
+
+FILE *runAdb(const Options &options, const QString &arguments)
+{
+ QString adb = options.sdkPath + QLatin1String("/platform-tools/adb");
+#if defined(Q_OS_WIN32)
+ adb += QLatin1String(".exe");
+#endif
+
+ if (!QFile::exists(adb)) {
+ fprintf(stderr, "Cannot find adb tool: %s\n", qPrintable(adb));
+ return 0;
+ }
+ QString installOption;
+ if (!options.installLocation.isEmpty())
+ installOption = QLatin1String(" -s ") + shellQuote(options.installLocation);
+
+ adb = QString::fromLatin1("%1%2 %3").arg(shellQuote(adb)).arg(installOption).arg(arguments);
+
+ if (options.verbose)
+ fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData());
+
+ FILE *adbCommand = openProcess(adb);
+ if (adbCommand == 0) {
+ fprintf(stderr, "Cannot start adb: %s\n", qPrintable(adb));
+ return 0;
+ }
+
+ return adbCommand;
+}
+
+bool goodToCopy(const Options *options, const QString &file, QStringList *unmetDependencies)
+{
+ if (!file.endsWith(QLatin1String(".so")))
+ return true;
+
+ bool ret = true;
+ const auto libs = getQtLibsFromElf(*options, file);
+ for (const QString &lib : libs) {
+ if (!options->qtDependencies.contains(QtDependency(lib, options->qtInstallDirectory + QLatin1Char('/') + lib))) {
+ ret = false;
+ unmetDependencies->append(lib);
+ }
+ }
+
+ return ret;
+}
+
+bool copyQtFiles(Options *options)
+{
+ if (options->verbose) {
+ switch (options->deploymentMechanism) {
+ case Options::Bundled:
+ fprintf(stdout, "Copying %d dependencies from Qt into package.\n", options->qtDependencies.size());
+ break;
+ case Options::Ministro:
+ fprintf(stdout, "Setting %d dependencies from Qt in package.\n", options->qtDependencies.size());
+ break;
+ };
+ }
+
+ if (!options->build)
+ return true;
+
+ QString libsDirectory = QLatin1String("libs/");
+
+ // Copy other Qt dependencies
+ QString libDestinationDirectory = libsDirectory + options->architecture + QLatin1Char('/');
+ QString assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/");
+ for (const QtDependency &qtDependency : qAsConst(options->qtDependencies)) {
+ QString sourceFileName = qtDependency.absolutePath;
+ QString destinationFileName;
+
+ if (qtDependency.relativePath.endsWith(QLatin1String(".so"))) {
+ QString garbledFileName;
+ if (qtDependency.relativePath.startsWith(QLatin1String("lib/"))) {
+ garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1);
+ } else {
+ garbledFileName = QLatin1String("lib")
+ + QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_'));
+
+ }
+ destinationFileName = libDestinationDirectory + garbledFileName;
+
+ } else if (qtDependency.relativePath.startsWith(QLatin1String("jar/"))) {
+ destinationFileName = libsDirectory + qtDependency.relativePath.mid(sizeof("jar/") - 1);
+ } else {
+ destinationFileName = assetsDestinationDirectory + qtDependency.relativePath;
+ }
+
+ if (!QFile::exists(sourceFileName)) {
+ fprintf(stderr, "Source Qt file does not exist: %s.\n", qPrintable(sourceFileName));
+ return false;
+ }
+
+ QStringList unmetDependencies;
+ if (!goodToCopy(options, sourceFileName, &unmetDependencies)) {
+ fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n",
+ qPrintable(sourceFileName),
+ qPrintable(unmetDependencies.join(QLatin1Char(','))));
+ continue;
+ }
+
+ if (options->deploymentMechanism == Options::Bundled
+ && !copyFileIfNewer(sourceFileName,
+ options->outputDirectory + QLatin1Char('/') + destinationFileName,
+ options->verbose)) {
+ return false;
+ }
+
+ options->bundledFiles += qMakePair(destinationFileName, qtDependency.relativePath);
+ }
+
+ return true;
+}
+
+QStringList getLibraryProjectsInOutputFolder(const Options &options)
+{
+ QStringList ret;
+
+ QFile file(options.outputDirectory + QLatin1String("/project.properties"));
+ if (file.open(QIODevice::ReadOnly)) {
+ while (!file.atEnd()) {
+ QByteArray line = file.readLine().trimmed();
+ if (line.startsWith("android.library.reference")) {
+ int equalSignIndex = line.indexOf('=');
+ if (equalSignIndex >= 0) {
+ QString path = QString::fromLocal8Bit(line.mid(equalSignIndex + 1));
+
+ QFileInfo info(options.outputDirectory + QLatin1Char('/') + path);
+ if (QDir::isRelativePath(path)
+ && info.exists()
+ && info.isDir()
+ && info.canonicalFilePath().startsWith(options.outputDirectory)) {
+ ret += info.canonicalFilePath();
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+bool createAndroidProject(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Running Android tool to create package definition.\n");
+
+ QString androidToolExecutable = options.sdkPath + QLatin1String("/tools/android");
+#if defined(Q_OS_WIN32)
+ androidToolExecutable += QLatin1String(".bat");
+#endif
+
+ if (!QFile::exists(androidToolExecutable)) {
+ fprintf(stderr, "Cannot find Android tool: %s\n", qPrintable(androidToolExecutable));
+ return false;
+ }
+
+ QString androidTool = QString::fromLatin1("%1 update project --path %2 --target %3 --name QtApp")
+ .arg(shellQuote(androidToolExecutable))
+ .arg(shellQuote(options.outputDirectory))
+ .arg(shellQuote(options.androidPlatform));
+
+ if (options.verbose)
+ fprintf(stdout, " -- Command: %s\n", qPrintable(androidTool));
+
+ FILE *androidToolCommand = openProcess(androidTool);
+ if (androidToolCommand == 0) {
+ fprintf(stderr, "Cannot run command '%s'\n", qPrintable(androidTool));
+ return false;
+ }
+
+ pclose(androidToolCommand);
+
+ // If the project has subprojects inside the current folder, we need to also run android update on these.
+ const QStringList libraryProjects = getLibraryProjectsInOutputFolder(options);
+ for (const QString &libraryProject : libraryProjects) {
+ if (options.verbose)
+ fprintf(stdout, "Updating subproject %s\n", qPrintable(libraryProject));
+
+ androidTool = QString::fromLatin1("%1 update lib-project --path %2 --target %3")
+ .arg(shellQuote(androidToolExecutable))
+ .arg(shellQuote(libraryProject))
+ .arg(shellQuote(options.androidPlatform));
+
+ if (options.verbose)
+ fprintf(stdout, " -- Command: %s\n", qPrintable(androidTool));
+
+ FILE *androidToolCommand = popen(androidTool.toLocal8Bit().constData(), "r");
+ if (androidToolCommand == 0) {
+ fprintf(stderr, "Cannot run command '%s'\n", qPrintable(androidTool));
+ return false;
+ }
+
+ pclose(androidToolCommand);
+ }
+
+ return true;
+}
+
+QString findInPath(const QString &fileName)
+{
+ const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
+#if defined(Q_OS_WIN32)
+ QLatin1Char separator(';');
+#else
+ QLatin1Char separator(':');
+#endif
+
+ const QStringList paths = path.split(separator);
+ for (const QString &path : paths) {
+ QFileInfo fileInfo(path + QLatin1Char('/') + fileName);
+ if (fileInfo.exists() && fileInfo.isFile() && fileInfo.isExecutable())
+ return path + QLatin1Char('/') + fileName;
+ }
+
+ return QString();
+}
+
+bool buildAntProject(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Building Android package using ant.\n");
+
+ QString antTool = options.antTool;
+ if (antTool.isEmpty()) {
+#if defined(Q_OS_WIN32)
+ antTool = findInPath(QLatin1String("ant.bat"));
+#else
+ antTool = findInPath(QLatin1String("ant"));
+#endif
+ }
+
+ if (antTool.isEmpty()) {
+ fprintf(stderr, "Cannot find ant in PATH. Please use --ant option to pass in the correct path.\n");
+ return false;
+ }
+
+ if (options.verbose)
+ fprintf(stdout, "Using ant: %s\n", qPrintable(antTool));
+
+ QString oldPath = QDir::currentPath();
+ if (!QDir::setCurrent(options.outputDirectory)) {
+ fprintf(stderr, "Cannot current path to %s\n", qPrintable(options.outputDirectory));
+ return false;
+ }
+
+ QString ant = QString::fromLatin1("%1 %2").arg(shellQuote(antTool)).arg(options.releasePackage ? QLatin1String(" release") : QLatin1String(" debug"));
+
+ FILE *antCommand = openProcess(ant);
+ if (antCommand == 0) {
+ fprintf(stderr, "Cannot run ant command: %s\n.", qPrintable(ant));
+ return false;
+ }
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), antCommand) != 0) {
+ fprintf(stdout, "%s", buffer);
+ fflush(stdout);
+ }
+
+ int errorCode = pclose(antCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "Building the android package failed!\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- For more information, run this command with --verbose.\n");
+ return false;
+ }
+
+ if (!QDir::setCurrent(oldPath)) {
+ fprintf(stderr, "Cannot change back to old path: %s\n", qPrintable(oldPath));
+ return false;
+ }
+
+ return true;
+}
+
+typedef QMap<QByteArray, QByteArray> GradleProperties;
+
+static GradleProperties readGradleProperties(const QString &path)
+{
+ GradleProperties properties;
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly))
+ return properties;
+
+ const auto lines = file.readAll().split('\n');
+ for (const QByteArray &line : lines) {
+ if (line.trimmed().startsWith('#'))
+ continue;
+
+ QList<QByteArray> prop(line.split('='));
+ if (prop.size() > 1)
+ properties[prop.at(0).trimmed()] = prop.at(1).trimmed();
+ }
+ file.close();
+ return properties;
+}
+
+static bool mergeGradleProperties(const QString &path, GradleProperties properties)
+{
+ QFile::remove(path + QLatin1Char('~'));
+ QFile::rename(path, path + QLatin1Char('~'));
+ QFile file(path);
+ if (!file.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) {
+ fprintf(stderr, "Can't open file: %s for writing\n", qPrintable(file.fileName()));
+ return false;
+ }
+
+ QFile oldFile(path + QLatin1Char('~'));
+ if (oldFile.open(QIODevice::ReadOnly)) {
+ while (!oldFile.atEnd()) {
+ QByteArray line(oldFile.readLine());
+ QList<QByteArray> prop(line.split('='));
+ if (prop.size() > 1) {
+ GradleProperties::iterator it = properties.find(prop.at(0).trimmed());
+ if (it != properties.end()) {
+ file.write(it.key() + '=' + it.value() + '\n');
+ properties.erase(it);
+ continue;
+ }
+ }
+ file.write(line);
+ }
+ oldFile.close();
+ }
+
+ for (GradleProperties::const_iterator it = properties.begin(); it != properties.end(); ++it)
+ file.write(it.key() + '=' + it.value() + '\n');
+
+ file.close();
+ return true;
+}
+
+bool buildGradleProject(const Options &options)
+{
+ GradleProperties localProperties;
+ localProperties["sdk.dir"] = options.sdkPath.toLocal8Bit();
+
+ if (!mergeGradleProperties(options.outputDirectory + QLatin1String("local.properties"), localProperties))
+ return false;
+
+ QString gradlePropertiesPath = options.outputDirectory + QLatin1String("gradle.properties");
+ GradleProperties gradleProperties = readGradleProperties(gradlePropertiesPath);
+ gradleProperties["buildDir"] = "build";
+ gradleProperties["qt5AndroidDir"] = (options.qtInstallDirectory + QLatin1String("/src/android/java")).toUtf8();
+ gradleProperties["androidCompileSdkVersion"] = options.androidPlatform.split(QLatin1Char('-')).last().toLocal8Bit();
+ if (gradleProperties["androidBuildToolsVersion"].isEmpty())
+ gradleProperties["androidBuildToolsVersion"] = options.sdkBuildToolsVersion.toLocal8Bit();
+
+ if (!mergeGradleProperties(gradlePropertiesPath, gradleProperties))
+ return false;
+
+#if defined(Q_OS_WIN32)
+ QString gradlePath(options.outputDirectory + QLatin1String("gradlew.bat"));
+#else
+ QString gradlePath(options.outputDirectory + QLatin1String("gradlew"));
+ {
+ QFile f(gradlePath);
+ if (!f.setPermissions(f.permissions() | QFileDevice::ExeUser))
+ fprintf(stderr, "Cannot set permissions %s\n", qPrintable(gradlePath));
+ }
+#endif
+
+ QString oldPath = QDir::currentPath();
+ if (!QDir::setCurrent(options.outputDirectory)) {
+ fprintf(stderr, "Cannot current path to %s\n", qPrintable(options.outputDirectory));
+ return false;
+ }
+
+ QString commandLine = QString::fromLatin1("%1 --no-daemon %2").arg(shellQuote(gradlePath)).arg(options.releasePackage ? QLatin1String(" assembleRelease") : QLatin1String(" assembleDebug"));
+ if (options.verbose)
+ commandLine += QLatin1String(" --info");
+
+ FILE *gradleCommand = openProcess(commandLine);
+ if (gradleCommand == 0) {
+ fprintf(stderr, "Cannot run gradle command: %s\n.", qPrintable(commandLine));
+ return false;
+ }
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), gradleCommand) != 0) {
+ fprintf(stdout, "%s", buffer);
+ fflush(stdout);
+ }
+
+ int errorCode = pclose(gradleCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "Building the android package failed!\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- For more information, run this command with --verbose.\n");
+ return false;
+ }
+
+ if (!QDir::setCurrent(oldPath)) {
+ fprintf(stderr, "Cannot change back to old path: %s\n", qPrintable(oldPath));
+ return false;
+ }
+
+ return true;
+}
+
+bool buildAndroidProject(const Options &options)
+{
+ return options.gradle ? buildGradleProject(options)
+ : buildAntProject(options);
+}
+
+bool uninstallApk(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Uninstalling old Android package %s if present.\n", qPrintable(options.packageName));
+
+
+ FILE *adbCommand = runAdb(options, QLatin1String(" uninstall ") + shellQuote(options.packageName));
+ if (adbCommand == 0)
+ return false;
+
+ if (options.verbose || mustReadOutputAnyway) {
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
+ if (options.verbose)
+ fprintf(stdout, "%s", buffer);
+ }
+
+ int returnCode = pclose(adbCommand);
+ if (returnCode != 0) {
+ fprintf(stderr, "Warning: Uninstall failed!\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+
+ return true;
+}
+
+enum PackageType {
+ UnsignedAPK,
+ SignedAPK
+};
+
+QString apkPath(const Options &options, PackageType pt)
+{
+ QString path(options.outputDirectory);
+ if (options.gradle)
+ path += QLatin1String("/build/outputs/apk/") + QDir(options.outputDirectory).dirName() + QLatin1Char('-');
+ else
+ path += QLatin1String("/bin/QtApp-");
+ if (options.releasePackage) {
+ path += QLatin1String("release-");
+ if (pt == UnsignedAPK)
+ path += QLatin1String("un");
+ path += QLatin1String("signed.apk");
+ } else {
+ path += QLatin1String("debug");
+ if (pt == SignedAPK)
+ path += QLatin1String("-signed");
+ path += QLatin1String(".apk");
+ }
+ return shellQuote(path);
+}
+
+bool installApk(const Options &options)
+{
+ fflush(stdout);
+ // Uninstall if necessary
+ if (options.uninstallApk)
+ uninstallApk(options);
+
+ if (options.verbose)
+ fprintf(stdout, "Installing Android package to device.\n");
+
+ FILE *adbCommand = runAdb(options,
+ QLatin1String(" install -r ")
+ + apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK
+ : SignedAPK));
+ if (adbCommand == 0)
+ return false;
+
+ if (options.verbose || mustReadOutputAnyway) {
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), adbCommand) != 0)
+ if (options.verbose)
+ fprintf(stdout, "%s", buffer);
+ }
+
+ int returnCode = pclose(adbCommand);
+ if (returnCode != 0) {
+ fprintf(stderr, "Installing to device failed!\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool copyStdCpp(Options *options)
+{
+ if (options->verbose)
+ fprintf(stdout, "Copying STL library\n");
+
+ QString filePath = !options->stdCppPath.isEmpty() ? options->stdCppPath
+ : options->ndkPath
+ + QLatin1String("/sources/cxx-stl/gnu-libstdc++/")
+ + options->toolchainVersion
+ + QLatin1String("/libs/")
+ + options->architecture
+ + QLatin1String("/libgnustl_shared.so");
+ if (!QFile::exists(filePath)) {
+ fprintf(stderr, "STL library does not exist at %s\n", qPrintable(filePath));
+ return false;
+ }
+
+ const QString destinationDirectory = options->outputDirectory
+ + QLatin1String("/libs/") + options->architecture;
+
+ if (!copyFileIfNewer(filePath, destinationDirectory + QLatin1String("/lib")
+ + options->stdCppName + QLatin1String(".so"),
+ options->verbose)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool jarSignerSignPackage(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Signing Android package.\n");
+
+ QString jdkPath = options.jdkPath;
+
+ if (jdkPath.isEmpty())
+ jdkPath = QString::fromLocal8Bit(qgetenv("JAVA_HOME"));
+
+#if defined(Q_OS_WIN32)
+ QString jarSignerTool = QString::fromLatin1("jarsigner.exe");
+#else
+ QString jarSignerTool = QString::fromLatin1("jarsigner");
+#endif
+
+ if (jdkPath.isEmpty() || !QFile::exists(jdkPath + QLatin1String("/bin/") + jarSignerTool))
+ jarSignerTool = findInPath(jarSignerTool);
+ else
+ jarSignerTool = jdkPath + QLatin1String("/bin/") + jarSignerTool;
+
+ if (!QFile::exists(jarSignerTool)) {
+ fprintf(stderr, "Cannot find jarsigner in JAVA_HOME or PATH. Please use --jdk option to pass in the correct path to JDK.\n");
+ return false;
+ }
+
+ jarSignerTool = QString::fromLatin1("%1 -sigalg %2 -digestalg %3 -keystore %4")
+ .arg(shellQuote(jarSignerTool)).arg(shellQuote(options.sigAlg)).arg(shellQuote(options.digestAlg)).arg(shellQuote(options.keyStore));
+
+ if (!options.keyStorePassword.isEmpty())
+ jarSignerTool += QString::fromLatin1(" -storepass %1").arg(shellQuote(options.keyStorePassword));
+
+ if (!options.storeType.isEmpty())
+ jarSignerTool += QString::fromLatin1(" -storetype %1").arg(shellQuote(options.storeType));
+
+ if (!options.keyPass.isEmpty())
+ jarSignerTool += QString::fromLatin1(" -keypass %1").arg(shellQuote(options.keyPass));
+
+ if (!options.sigFile.isEmpty())
+ jarSignerTool += QString::fromLatin1(" -sigfile %1").arg(shellQuote(options.sigFile));
+
+ if (!options.signedJar.isEmpty())
+ jarSignerTool += QString::fromLatin1(" -signedjar %1").arg(shellQuote(options.signedJar));
+
+ if (!options.tsaUrl.isEmpty())
+ jarSignerTool += QString::fromLatin1(" -tsa %1").arg(shellQuote(options.tsaUrl));
+
+ if (!options.tsaCert.isEmpty())
+ jarSignerTool += QString::fromLatin1(" -tsacert %1").arg(shellQuote(options.tsaCert));
+
+ if (options.internalSf)
+ jarSignerTool += QLatin1String(" -internalsf");
+
+ if (options.sectionsOnly)
+ jarSignerTool += QLatin1String(" -sectionsonly");
+
+ if (options.protectedAuthenticationPath)
+ jarSignerTool += QLatin1String(" -protected");
+
+ jarSignerTool += QString::fromLatin1(" %1 %2")
+ .arg(apkPath(options, UnsignedAPK))
+ .arg(shellQuote(options.keyStoreAlias));
+
+ FILE *jarSignerCommand = openProcess(jarSignerTool);
+ if (jarSignerCommand == 0) {
+ fprintf(stderr, "Couldn't run jarsigner.\n");
+ return false;
+ }
+
+ if (options.verbose) {
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0)
+ fprintf(stdout, "%s", buffer);
+ }
+
+ int errorCode = pclose(jarSignerCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "jarsigner command failed.\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+
+ QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign");
+#if defined(Q_OS_WIN32)
+ zipAlignTool += QLatin1String(".exe");
+#endif
+
+ if (!QFile::exists(zipAlignTool)) {
+ zipAlignTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/zipalign");
+#if defined(Q_OS_WIN32)
+ zipAlignTool += QLatin1String(".exe");
+#endif
+ if (!QFile::exists(zipAlignTool)) {
+ fprintf(stderr, "zipalign tool not found: %s\n", qPrintable(zipAlignTool));
+ return false;
+ }
+ }
+
+ zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4")
+ .arg(shellQuote(zipAlignTool))
+ .arg(options.verbose ? QString::fromLatin1(" -v") : QString())
+ .arg(apkPath(options, UnsignedAPK))
+ .arg(apkPath(options, SignedAPK));
+
+ FILE *zipAlignCommand = openProcess(zipAlignTool);
+ if (zipAlignCommand == 0) {
+ fprintf(stderr, "Couldn't run zipalign.\n");
+ return false;
+ }
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0)
+ fprintf(stdout, "%s", buffer);
+
+ errorCode = pclose(zipAlignCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "zipalign command failed.\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+
+ return QFile::remove(apkPath(options, UnsignedAPK));
+}
+
+bool signPackage(const Options &options)
+{
+ QString apksignerTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/apksigner");
+#if defined(Q_OS_WIN32)
+ apksignerTool += QLatin1String(".bat");
+#endif
+
+ if (options.jarSigner || !QFile::exists(apksignerTool))
+ return jarSignerSignPackage(options);
+
+ // APKs signed with apksigner must not be changed after they're signed, therefore we need to zipalign it before we sign it.
+
+ QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign");
+#if defined(Q_OS_WIN32)
+ zipAlignTool += QLatin1String(".exe");
+#endif
+
+ if (!QFile::exists(zipAlignTool)) {
+ zipAlignTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/zipalign");
+#if defined(Q_OS_WIN32)
+ zipAlignTool += QLatin1String(".exe");
+#endif
+ if (!QFile::exists(zipAlignTool)) {
+ fprintf(stderr, "zipalign tool not found: %s\n", qPrintable(zipAlignTool));
+ return false;
+ }
+ }
+
+ zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4")
+ .arg(shellQuote(zipAlignTool))
+ .arg(options.verbose ? QString::fromLatin1(" -v") : QString())
+ .arg(apkPath(options, UnsignedAPK))
+ .arg(apkPath(options, SignedAPK));
+
+ FILE *zipAlignCommand = openProcess(zipAlignTool);
+ if (zipAlignCommand == 0) {
+ fprintf(stderr, "Couldn't run zipalign.\n");
+ return false;
+ }
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0)
+ fprintf(stdout, "%s", buffer);
+
+ int errorCode = pclose(zipAlignCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "zipalign command failed.\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+
+ QString apkSignerCommandLine = QString::fromLatin1("%1 sign --ks %2")
+ .arg(shellQuote(apksignerTool)).arg(shellQuote(options.keyStore));
+
+ if (!options.keyStorePassword.isEmpty())
+ apkSignerCommandLine += QString::fromLatin1(" --ks-pass pass:%1").arg(shellQuote(options.keyStorePassword));
+
+ if (!options.keyStoreAlias.isEmpty())
+ apkSignerCommandLine += QString::fromLatin1(" --ks-key-alias %1").arg(shellQuote(options.keyStoreAlias));
+
+ if (!options.keyPass.isEmpty())
+ apkSignerCommandLine += QString::fromLatin1(" --key-pass pass:%1").arg(shellQuote(options.keyPass));
+
+ if (options.verbose)
+ apkSignerCommandLine += QLatin1String(" --verbose");
+
+ apkSignerCommandLine += QString::fromLatin1(" %1")
+ .arg(apkPath(options, SignedAPK));
+
+ auto apkSignerRunner = [&] {
+ FILE *apkSignerCommand = openProcess(apkSignerCommandLine);
+ if (apkSignerCommand == 0) {
+ fprintf(stderr, "Couldn't run apksigner.\n");
+ return false;
+ }
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), apkSignerCommand) != 0)
+ fprintf(stdout, "%s", buffer);
+
+ errorCode = pclose(apkSignerCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "apksigner command failed.\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+ return true;
+ };
+
+ // Sign the package
+ if (!apkSignerRunner())
+ return false;
+
+ apkSignerCommandLine = QString::fromLatin1("%1 verify --verbose %2")
+ .arg(shellQuote(apksignerTool)).arg(apkPath(options, SignedAPK));
+
+ // Verify the package and remove the unsigned apk
+ return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK));
+}
+
+bool copyGdbServer(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Copying gdbserver into package.\n");
+
+ QString architectureSubDirectory;
+ if (options.architecture == QLatin1String("arm64-v8a"))
+ architectureSubDirectory = QLatin1String("android-arm64");
+ else if (options.architecture.startsWith(QLatin1String("arm")))
+ architectureSubDirectory = QLatin1String("android-arm");
+ else
+ architectureSubDirectory = QLatin1String("android-") + options.architecture;
+
+ QString gdbServerBinary = options.ndkPath
+ + QLatin1String("/prebuilt/")
+ + architectureSubDirectory
+ + QLatin1String("/gdbserver/gdbserver");
+ if (!QFile::exists(gdbServerBinary)) {
+ fprintf(stderr, "Cannot find gdbserver at %s.\n", qPrintable(gdbServerBinary));
+ return false;
+ }
+
+ QString gdbServerTarget = options.outputDirectory + QLatin1String("/libs/") + options.architecture;
+
+ if (!copyFileIfNewer(gdbServerBinary,
+ gdbServerTarget + QLatin1String("/gdbserver"),
+ options.verbose)
+ || !copyFileIfNewer(gdbServerBinary,
+ gdbServerTarget + QLatin1String("/libgdbserver.so"),
+ options.verbose)) {
+ return false;
+ }
+
+ QString addedByAndroidDeployQtPath = options.outputDirectory + QLatin1String("/assets/--Added-by-androiddeployqt--/");
+ if (!QDir().mkpath(addedByAndroidDeployQtPath)) {
+ fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath));
+ return false;
+ }
+ QFile f(addedByAndroidDeployQtPath + QLatin1String("debugger.command"));
+ if (!f.open(QIODevice::WriteOnly)) {
+ fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath));
+ return false;
+ }
+ f.write("lib/libgdbserver.so --multi +");
+ f.close();
+
+ return true;
+}
+
+bool generateAssetsFileList(const Options &options)
+{
+ if (options.verbose)
+ fprintf(stdout, "Pregenerating entry list for assets file engine.\n");
+
+ QString assetsPath = options.outputDirectory + QLatin1String("/assets/");
+ QString addedByAndroidDeployQtPath = assetsPath + QLatin1String("--Added-by-androiddeployqt--/");
+ if (!QDir().mkpath(addedByAndroidDeployQtPath)) {
+ fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath));
+ return false;
+ }
+
+ QFile file(addedByAndroidDeployQtPath + QLatin1String("/qt_cache_pregenerated_file_list"));
+ if (file.open(QIODevice::WriteOnly)) {
+ QDirIterator dirIterator(assetsPath,
+ QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot,
+ QDirIterator::Subdirectories);
+
+ QHash<QString, QStringList> directoryContents;
+ while (dirIterator.hasNext()) {
+ const QString name = dirIterator.next().mid(assetsPath.length());
+
+ int slashIndex = name.lastIndexOf(QLatin1Char('/'));
+ QString pathName = slashIndex >= 0 ? name.left(slashIndex) : QString::fromLatin1("/");
+ QString fileName = slashIndex >= 0 ? name.mid(pathName.length() + 1) : name;
+
+ if (!fileName.isEmpty() && dirIterator.fileInfo().isDir() && !fileName.endsWith(QLatin1Char('/')))
+ fileName += QLatin1Char('/');
+
+ if (fileName.isEmpty() && !directoryContents.contains(pathName))
+ directoryContents[pathName] = QStringList();
+ else if (!fileName.isEmpty())
+ directoryContents[pathName].append(fileName);
+ }
+
+ QDataStream stream(&file);
+ stream.setVersion(QDataStream::Qt_5_3);
+ for (auto it = directoryContents.cbegin(), end = directoryContents.cend(); it != end; ++it) {
+ const QStringList &entryList = it.value();
+ stream << it.key() << entryList.size();
+ for (const QString &entry : entryList)
+ stream << entry;
+ }
+ } else {
+ fprintf(stderr, "Pregenerating entry list for assets file engine failed!\n");
+ return false;
+ }
+
+ return true;
+}
+
+enum ErrorCode
+{
+ Success,
+ SyntaxErrorOrHelpRequested = 1,
+ CannotReadInputFile = 2,
+ CannotCopyAndroidTemplate = 3,
+ CannotReadDependencies = 4,
+ CannotCopyGnuStl = 5,
+ CannotCopyQtFiles = 6,
+ CannotFindApplicationBinary = 7,
+ CannotCopyGdbServer = 8,
+ CannotStripLibraries = 9,
+ CannotCopyAndroidExtraLibs = 10,
+ CannotCopyAndroidSources = 11,
+ CannotUpdateAndroidFiles = 12,
+ CannotCreateAndroidProject = 13,
+ CannotBuildAndroidProject = 14,
+ CannotSignPackage = 15,
+ CannotInstallApk = 16,
+ CannotGenerateAssetsFileList = 18,
+ CannotCopyAndroidExtraResources = 19
+};
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+
+ Options options = parseOptions();
+ if (options.helpRequested || options.outputDirectory.isEmpty()) {
+ printHelp();
+ return SyntaxErrorOrHelpRequested;
+ }
+
+ options.timer.start();
+
+ if (!readInputFile(&options))
+ return CannotReadInputFile;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Read input file\n", options.timer.elapsed());
+
+ fprintf(stdout,
+// "012345678901234567890123456789012345678901234567890123456789012345678901"
+ "Generating Android Package\n"
+ " Input file: %s\n"
+ " Output directory: %s\n"
+ " Application binary: %s\n"
+ " Android build platform: %s\n"
+ " Install to device: %s\n",
+ qPrintable(options.inputFileName),
+ qPrintable(options.outputDirectory),
+ qPrintable(options.applicationBinary),
+ qPrintable(options.androidPlatform),
+ options.installApk
+ ? (options.installLocation.isEmpty() ? "Default device" : qPrintable(options.installLocation))
+ : "No"
+ );
+
+ if (options.build) {
+ if (options.gradle)
+ cleanAndroidFiles(options);
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Cleaned Android file\n", options.timer.elapsed());
+
+ if (!copyAndroidTemplate(options))
+ return CannotCopyAndroidTemplate;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Copied Android template\n", options.timer.elapsed());
+ }
+
+ if (!readDependencies(&options))
+ return CannotReadDependencies;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed());
+
+ if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options))
+ return CannotCopyGnuStl;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed());
+
+ if (!copyQtFiles(&options))
+ return CannotCopyQtFiles;
+
+ if (options.build) {
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Copied Qt files\n", options.timer.elapsed());
+
+ if (!containsApplicationBinary(options))
+ return CannotFindApplicationBinary;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed());
+
+ bool needToCopyGdbServer = options.gdbServer == Options::True
+ || (options.gdbServer == Options::Auto && !options.releasePackage);
+ if (needToCopyGdbServer && !copyGdbServer(options))
+ return CannotCopyGdbServer;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Copied GDB server\n", options.timer.elapsed());
+
+ if (!copyAndroidExtraLibs(options))
+ return CannotCopyAndroidExtraLibs;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed());
+
+ if (!copyAndroidExtraResources(options))
+ return CannotCopyAndroidExtraResources;
+
+ if (!copyAndroidSources(options))
+ return CannotCopyAndroidSources;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Copied android sources\n", options.timer.elapsed());
+
+ if (!stripLibraries(options))
+ return CannotStripLibraries;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Stripped libraries\n", options.timer.elapsed());
+
+ if (!updateAndroidFiles(options))
+ return CannotUpdateAndroidFiles;
+
+ if (options.generateAssetsFileList && !generateAssetsFileList(options))
+ return CannotGenerateAssetsFileList;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Updated files\n", options.timer.elapsed());
+
+ if (!options.gradle && !createAndroidProject(options))
+ return CannotCreateAndroidProject;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Created project\n", options.timer.elapsed());
+
+ if (!buildAndroidProject(options))
+ return CannotBuildAndroidProject;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Built project\n", options.timer.elapsed());
+
+ if (!options.keyStore.isEmpty() && !signPackage(options))
+ return CannotSignPackage;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Signed package\n", options.timer.elapsed());
+ }
+
+ if (options.installApk && !installApk(options))
+ return CannotInstallApk;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Installed APK\n", options.timer.elapsed());
+
+ fprintf(stdout, "Android package built successfully in %.3f ms.\n", options.timer.elapsed() / 1000.);
+
+ if (options.installApk)
+ fprintf(stdout, " -- It can now be run from the selected device/emulator.\n");
+
+ fprintf(stdout, " -- File: %s\n", qPrintable(apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK
+ : SignedAPK)));
+ fflush(stdout);
+ return 0;
+}
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index 8248676a9f..2742b152f2 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -1463,19 +1463,6 @@ void QFileDialog::selectNameFilter(const QString &filter)
}
/*!
- * \since 5.9
- * \return The mimetype of the file that the user selected in the file dialog.
- */
-QString QFileDialog::selectedMimeTypeFilter() const
-{
- Q_D(const QFileDialog);
- if (!d->usingWidgets())
- return d->selectedMimeTypeFilter_sys();
-
- return d->options->initiallySelectedMimeTypeFilter();
-}
-
-/*!
\since 4.4
Returns the filter that the user selected in the file dialog.
@@ -1612,6 +1599,36 @@ void QFileDialog::selectMimeTypeFilter(const QString &filter)
#endif // QT_NO_MIMETYPE
/*!
+ * \since 5.9
+ * \return The mimetype of the file that the user selected in the file dialog.
+ */
+QString QFileDialog::selectedMimeTypeFilter() const
+{
+ Q_D(const QFileDialog);
+ QString mimeTypeFilter;
+ if (!d->usingWidgets())
+ mimeTypeFilter = d->selectedMimeTypeFilter_sys();
+
+#ifndef QT_NO_MIMETYPE
+ if (mimeTypeFilter.isNull() && !d->options->mimeTypeFilters().isEmpty()) {
+ const auto nameFilter = selectedNameFilter();
+ const auto mimeTypes = d->options->mimeTypeFilters();
+ for (const auto &mimeType: mimeTypes) {
+ QString filter = nameFilterForMime(mimeType);
+ if (testOption(HideNameFilterDetails))
+ filter = qt_strip_filters({ filter }).first();
+ if (filter == nameFilter) {
+ mimeTypeFilter = mimeType;
+ break;
+ }
+ }
+ }
+#endif
+
+ return mimeTypeFilter;
+}
+
+/*!
\property QFileDialog::viewMode
\brief the way files and directories are displayed in the dialog
diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp
index 38df9e72bd..203b879020 100644
--- a/src/widgets/graphicsview/qgraphicsitem.cpp
+++ b/src/widgets/graphicsview/qgraphicsitem.cpp
@@ -1579,6 +1579,7 @@ QGraphicsItem::~QGraphicsItem()
QObjectPrivate *p = QObjectPrivate::get(o);
p->wasDeleted = true;
if (p->declarativeData) {
+ p->wasDeleted = true; // needed, so that destroying the declarative data does the right thing
if (static_cast<QAbstractDeclarativeDataImpl*>(p->declarativeData)->ownedByQml1) {
if (QAbstractDeclarativeData::destroyed_qml1)
QAbstractDeclarativeData::destroyed_qml1(p->declarativeData, o);
@@ -1587,6 +1588,7 @@ QGraphicsItem::~QGraphicsItem()
QAbstractDeclarativeData::destroyed(p->declarativeData, o);
}
p->declarativeData = 0;
+ p->wasDeleted = false;
}
}
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
index 6dc0543255..762e852f88 100644
--- a/src/widgets/itemviews/qheaderview.cpp
+++ b/src/widgets/itemviews/qheaderview.cpp
@@ -2727,7 +2727,7 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e)
statusTip = d->model->headerData(logical, d->orientation, Qt::StatusTipRole).toString();
if (d->shouldClearStatusTip || !statusTip.isEmpty()) {
QStatusTipEvent tip(statusTip);
- QCoreApplication::sendEvent(d->parent, &tip);
+ QCoreApplication::sendEvent(d->parent ? d->parent : this, &tip);
d->shouldClearStatusTip = !statusTip.isEmpty();
}
#endif // !QT_NO_STATUSTIP
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index e59bd4098d..9a19597cad 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1677,8 +1677,8 @@ QWidget::~QWidget()
}
}
- d->wasDeleted = true;
if (d->declarativeData) {
+ d->wasDeleted = true; // needed, so that destroying the declarative data does the right thing
if (static_cast<QAbstractDeclarativeDataImpl*>(d->declarativeData)->ownedByQml1) {
if (QAbstractDeclarativeData::destroyed_qml1)
QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this);
@@ -1687,6 +1687,7 @@ QWidget::~QWidget()
QAbstractDeclarativeData::destroyed(d->declarativeData, this);
}
d->declarativeData = 0; // don't activate again in ~QObject
+ d->wasDeleted = false;
}
d->blockSig = blocked;
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp
index 4758f64c8c..6df53dc4e4 100644
--- a/src/widgets/widgets/qmenubar.cpp
+++ b/src/widgets/widgets/qmenubar.cpp
@@ -327,7 +327,7 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst)
QRect screenRect = QDesktopWidgetPrivate::screenGeometry(pos + QPoint(adjustedActionRect.width() / 2, 0));
pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y()));
- const bool fitUp = (q->mapToGlobal(adjustedActionRect.topLeft()).y() >= popup_size.height());
+ const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top());
const bool fitDown = (pos.y() + popup_size.height() <= screenRect.bottom());
const bool rtl = q->isRightToLeft();
const int actionWidth = adjustedActionRect.width();
@@ -1209,8 +1209,15 @@ void QMenuBar::keyPressEvent(QKeyEvent *e)
void QMenuBar::mouseMoveEvent(QMouseEvent *e)
{
Q_D(QMenuBar);
- if (!(e->buttons() & Qt::LeftButton))
+ if (!(e->buttons() & Qt::LeftButton)) {
d->mouseDown = false;
+ // We receive mouse move and mouse press on touch.
+ // Mouse move will open the menu and mouse press
+ // will close it, so ignore mouse move.
+ if (e->source() != Qt::MouseEventNotSynthesized)
+ return;
+ }
+
bool popupState = d->popupState || d->mouseDown;
QAction *action = d->actionAt(e->pos());
if ((action && d->isVisible(action)) || !popupState)
diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp
index f15a846b5e..252d5a79df 100644
--- a/src/widgets/widgets/qplaintextedit.cpp
+++ b/src/widgets/widgets/qplaintextedit.cpp
@@ -110,7 +110,7 @@ public:
/*! \class QPlainTextDocumentLayout
\since 4.4
- \brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument
+ \brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument.
\ingroup richtext-processing
\inmodule QtWidgets
diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp
index bbcd3ca386..3a368651de 100644
--- a/src/widgets/widgets/qtextedit.cpp
+++ b/src/widgets/widgets/qtextedit.cpp
@@ -2048,7 +2048,7 @@ void QTextEdit::setAcceptRichText(bool accept)
\inmodule QtWidgets
\brief The QTextEdit::ExtraSelection structure provides a way of specifying a
- character format for a given selection in a document
+ character format for a given selection in a document.
*/
/*!