summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/Qt6AndroidMacros.cmake21
-rw-r--r--src/corelib/configure.cmake9
-rw-r--r--src/corelib/doc/src/cmake/qt_add_android_dynamic_feature_java_source_dirs.qdoc30
-rw-r--r--src/corelib/doc/src/cmake/qt_add_android_permission.qdoc4
-rw-r--r--src/corelib/global/qcompilerdetection.h2
-rw-r--r--src/corelib/itemmodels/qrangemodel_impl.h41
-rw-r--r--src/corelib/kernel/qobject.cpp35
-rw-r--r--src/corelib/kernel/qpermissions.cpp6
-rw-r--r--src/corelib/platform/wasm/qstdweb.cpp113
-rw-r--r--src/corelib/platform/wasm/qstdweb_p.h81
10 files changed, 299 insertions, 43 deletions
diff --git a/src/corelib/Qt6AndroidMacros.cmake b/src/corelib/Qt6AndroidMacros.cmake
index 6a83e947146..be362ba1925 100644
--- a/src/corelib/Qt6AndroidMacros.cmake
+++ b/src/corelib/Qt6AndroidMacros.cmake
@@ -106,6 +106,27 @@ function(qt6_add_android_dynamic_features target)
endif()
endfunction()
+
+function(qt_add_android_dynamic_feature_java_source_dirs)
+ qt6_add_android_dynamic_feature_java_source_dirs(${ARGV})
+endfunction()
+
+# Add java source directories for dynamic feature. Intermediate solution until java library
+# support exists.
+function(qt6_add_android_dynamic_feature_java_source_dirs target)
+
+ set(opt_args "")
+ set(single_args "")
+ set(multi_args
+ SOURCE_DIRS
+ )
+ cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
+ if(arg_SOURCE_DIRS)
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_android_gradle_java_source_dirs ${arg_SOURCE_DIRS})
+ endif()
+endfunction()
+
# Generate the deployment settings json file for a cmake target.
function(qt6_android_generate_deployment_settings target)
# Information extracted from mkspecs/features/android/android_deployment_settings.prf
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index edcfba0f6ce..08908082991 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -31,7 +31,10 @@ qt_find_package_extend_sbom(TARGETS GLIB2::GLIB2
LICENSE_EXPRESSION "LGPL-2.1-or-later"
)
qt_find_package(ICU 50.1 COMPONENTS i18n uc data PROVIDED_TARGETS ICU::i18n ICU::uc ICU::data
- MODULE_NAME core QMAKE_LIB icu)
+ MODULE_NAME core QMAKE_LIB icu
+ VCPKG_PORT icu
+ VCPKG_PLATFORM !windows
+)
if(QT_FEATURE_dlopen)
qt_add_qmake_lib_dependency(icu libdl)
@@ -49,7 +52,9 @@ qt_find_package_extend_sbom(TARGETS Libb2::Libb2
qt_find_package(WrapRt MODULE
PROVIDED_TARGETS WrapRt::WrapRt MODULE_NAME core QMAKE_LIB librt)
qt_find_package(WrapSystemPCRE2 10.20 MODULE
- PROVIDED_TARGETS WrapSystemPCRE2::WrapSystemPCRE2 MODULE_NAME core QMAKE_LIB pcre2)
+ PROVIDED_TARGETS WrapSystemPCRE2::WrapSystemPCRE2 MODULE_NAME core QMAKE_LIB pcre2
+ VCPKG_PORT pcre2
+)
set_package_properties(WrapPCRE2 PROPERTIES TYPE REQUIRED)
if((QNX) OR QT_FIND_ALL_PACKAGES_ALWAYS)
qt_find_package(PPS MODULE PROVIDED_TARGETS PPS::PPS MODULE_NAME core QMAKE_LIB pps)
diff --git a/src/corelib/doc/src/cmake/qt_add_android_dynamic_feature_java_source_dirs.qdoc b/src/corelib/doc/src/cmake/qt_add_android_dynamic_feature_java_source_dirs.qdoc
new file mode 100644
index 00000000000..cf670110cab
--- /dev/null
+++ b/src/corelib/doc/src/cmake/qt_add_android_dynamic_feature_java_source_dirs.qdoc
@@ -0,0 +1,30 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt_add_android_dynamic_feature_java_source_dirs.html
+\ingroup cmake-commands-qtcore
+
+\title qt_add_android_dynamic_feature_java_source_dirs
+\keyword qt6_add_android_dynamic_feature_java_source_dirs
+
+\summary {Adds Java source directories to a dynamic feature build.}
+
+\include cmake-find-package-core.qdocinc
+
+\cmakecommandsince 6.11
+
+\section1 Synopsis
+
+\badcode
+qt_add_android_dynamic_feature_java_source_dirs(target [SOURCE_DIRS <directory1> <directory2> ...])
+\endcode
+
+\versionlessCMakeCommandsNote qt6_add_android_dynamic_feature_java_source_dirs()
+
+\section1 Description
+
+The command adds extra Java/Kotlin source directories to the \c {target}
+executable when building the executable app with dynamic feature functionality.
+To be used in conjunction with qt6_add_android_dynamic_features().
+*/
diff --git a/src/corelib/doc/src/cmake/qt_add_android_permission.qdoc b/src/corelib/doc/src/cmake/qt_add_android_permission.qdoc
index 68fe6a8e5cc..8fa6c2bb6d7 100644
--- a/src/corelib/doc/src/cmake/qt_add_android_permission.qdoc
+++ b/src/corelib/doc/src/cmake/qt_add_android_permission.qdoc
@@ -14,6 +14,10 @@
\cmakecommandsince 6.9
+\note When using this API, the \c{<!-- %%INSERT_PERMISSIONS -->} tag must be present
+in the AndroidManifest.xml. For further information on the use of this tag,
+see \l {Qt Permissions and Features}
+
\section1 Synopsis
\badcode
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 7bb2e5b04ef..0b42af7686c 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -1446,7 +1446,7 @@ QT_WARNING_DISABLE_MSVC(4355) /* 'this' : used in base member initializer list *
QT_WARNING_DISABLE_MSVC(4710) /* function not inlined */
QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc */
# elif defined(Q_CC_CLANG_ONLY)
-# if Q_CC_CLANG >= 2100
+# if __has_warning("-Wcharacter-conversion")
QT_WARNING_DISABLE_CLANG("-Wcharacter-conversion") /* until https://github.com/llvm/llvm-project/issues/163719 is fixed */
# endif
# elif defined(Q_CC_BOR)
diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h
index 70552cbfe05..88bd6cf444e 100644
--- a/src/corelib/itemmodels/qrangemodel_impl.h
+++ b/src/corelib/itemmodels/qrangemodel_impl.h
@@ -28,7 +28,7 @@
#include <functional>
#include <iterator>
#include <type_traits>
-#include <QtCore/q20type_traits.h>
+#include <QtCore/qxptype_traits.h>
#include <tuple>
#include <QtCore/q23utility.h>
@@ -562,35 +562,30 @@ namespace QRangeModelDetails
}
};
- template <typename P, typename R, typename = void>
- struct protocol_parentRow : std::false_type {};
template <typename P, typename R>
- struct protocol_parentRow<P, R,
- std::void_t<decltype(std::declval<P&>().parentRow(std::declval<wrapped_t<R>&>()))>>
- : std::true_type {};
+ using protocol_parentRow_test = decltype(std::declval<P&>()
+ .parentRow(std::declval<QRangeModelDetails::wrapped_t<R>&>()));
+ template <typename P, typename R>
+ using protocol_parentRow = qxp::is_detected<protocol_parentRow_test, P, R>;
- template <typename P, typename R, typename = void>
- struct protocol_childRows : std::false_type {};
template <typename P, typename R>
- struct protocol_childRows<P, R,
- std::void_t<decltype(std::declval<P&>().childRows(std::declval<wrapped_t<R>&>()))>>
- : std::true_type {};
+ using protocol_childRows_test = decltype(std::declval<P&>()
+ .childRows(std::declval<QRangeModelDetails::wrapped_t<R>&>()));
+ template <typename P, typename R>
+ using protocol_childRows = qxp::is_detected<protocol_childRows_test, P, R>;
- template <typename P, typename R, typename = void>
- struct protocol_setParentRow : std::false_type {};
template <typename P, typename R>
- struct protocol_setParentRow<P, R,
- std::void_t<decltype(std::declval<P&>().setParentRow(std::declval<wrapped_t<R>&>(),
- std::declval<wrapped_t<R>*>()))>>
- : std::true_type {};
+ using protocol_setParentRow_test = decltype(std::declval<P&>()
+ .setParentRow(std::declval<QRangeModelDetails::wrapped_t<R>&>(),
+ std::declval<QRangeModelDetails::wrapped_t<R>*>()));
+ template <typename P, typename R>
+ using protocol_setParentRow = qxp::is_detected<protocol_setParentRow_test, P, R>;
- template <typename P, typename R, typename = void>
- struct protocol_mutable_childRows : std::false_type {};
template <typename P, typename R>
- struct protocol_mutable_childRows<P, R,
- std::void_t<decltype(refTo(std::declval<P&>().childRows(std::declval<wrapped_t<R>&>()))
- = {}) >>
- : std::true_type {};
+ using protocol_mutable_childRows_test = decltype(refTo(std::declval<P&>()
+ .childRows(std::declval<wrapped_t<R>&>())) = {});
+ template <typename P, typename R>
+ using protocol_mutable_childRows = qxp::is_detected<protocol_mutable_childRows_test, P, R>;
template <typename P, typename = void>
struct protocol_newRow : std::false_type {};
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 02c9f00f301..607dc23f56c 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -2696,23 +2696,38 @@ static void err_method_notfound(const QObject *object,
case QSIGNAL_CODE: type = "signal"; break;
}
const char *loc = extract_location(method);
+ const char *err;
if (strchr(method, ')') == nullptr) // common typing mistake
- qCWarning(lcConnect, "QObject::%s: Parentheses expected, %s %s::%s%s%s", func, type,
- object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
+ err = "Parentheses expected,";
else
- qCWarning(lcConnect, "QObject::%s: No such %s %s::%s%s%s", func, type,
- object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
+ err = "No such";
+ qCWarning(lcConnect, "QObject::%s: %s %s %s::%s%s%s", func, err, type,
+ object->metaObject()->className(), method + 1, loc ? " in " : "", loc ? loc : "");
+}
+
+enum class ConnectionEnd : bool { Sender, Receiver };
+Q_DECL_COLD_FUNCTION
+static void err_info_about_object(const char *func, const QObject *o, ConnectionEnd end)
+{
+ if (!o)
+ return;
+ const QString name = o->objectName();
+ if (name.isEmpty())
+ return;
+ const bool sender = end == ConnectionEnd::Sender;
+ qCWarning(lcConnect, "QObject::%s: (%s name:%*s'%ls')",
+ func,
+ sender ? "sender" : "receiver",
+ sender ? 3 : 1, // ← length of generated whitespace
+ "",
+ qUtf16Printable(name));
}
Q_DECL_COLD_FUNCTION
static void err_info_about_objects(const char *func, const QObject *sender, const QObject *receiver)
{
- QString a = sender ? sender->objectName() : QString();
- QString b = receiver ? receiver->objectName() : QString();
- if (!a.isEmpty())
- qCWarning(lcConnect, "QObject::%s: (sender name: '%s')", func, a.toLocal8Bit().data());
- if (!b.isEmpty())
- qCWarning(lcConnect, "QObject::%s: (receiver name: '%s')", func, b.toLocal8Bit().data());
+ err_info_about_object(func, sender, ConnectionEnd::Sender);
+ err_info_about_object(func, receiver, ConnectionEnd::Receiver);
}
Q_DECL_COLD_FUNCTION
diff --git a/src/corelib/kernel/qpermissions.cpp b/src/corelib/kernel/qpermissions.cpp
index bbcea8338ca..6767917e176 100644
--- a/src/corelib/kernel/qpermissions.cpp
+++ b/src/corelib/kernel/qpermissions.cpp
@@ -124,7 +124,11 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg);
The relevant permission names are described in the documentation
for each permission type.
- \sa {Qt Creator: Editing Manifest Files}
+ \note When using this API, the \c{<!-- %%INSERT_PERMISSIONS -->} tag must be present in
+ the AndroidManifest.xml. For further information on the use of this tag,
+ see \l {Qt Permissions and Features}
+
+ \sa {Qt Creator: Editing Manifest Files}.
\section1 Available Permissions
diff --git a/src/corelib/platform/wasm/qstdweb.cpp b/src/corelib/platform/wasm/qstdweb.cpp
index 4f3ecc4c6d9..bbaf2c442a0 100644
--- a/src/corelib/platform/wasm/qstdweb.cpp
+++ b/src/corelib/platform/wasm/qstdweb.cpp
@@ -446,6 +446,119 @@ EventCallback::EventCallback(emscripten::val element, const std::string &name,
}
+size_t qstdweb::Promise::State::s_numInstances = 0;
+
+//
+// When a promise settles, all attached handlers will be called in
+// the order they where added.
+//
+// In particular a finally handler will be called according to its
+// position in the call chain. Which is not necessarily at the end,
+//
+// This makes cleanup difficult. If we cleanup to early, we will remove
+// handlers before they have a chance to be called. This would be the
+// case if we add a finally handler in the Promise constructor.
+//
+// For correct cleanup it is necessary that it happens after the
+// last handler has been called.
+//
+// We choose to implement this by making sure the last handler
+// is always a finally handler.
+//
+// In this case we have multiple finally handlers, so any called
+// handler checks if it is the last handler to be called.
+// If it is, the cleanup is performed, otherwise cleanup
+// is delayed to the last handler.
+//
+// We could try to let the handlers cleanup themselves, but this
+// only works for finally handlers. A then or catch handler is not
+// necessarily called, and would not cleanup itself.
+//
+// We could try to let a (then,catch) pair cleanup both handlers,
+// under the assumption that one of them will always be called.
+// This does not work in the case that we do not have both handlers,
+// or if the then handler throws (both should be called in this case).
+//
+Promise& Promise::addThenFunction(std::function<void(emscripten::val)> thenFunc)
+{
+ QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get();
+ Q_ASSERT(suspendResume);
+
+ m_state->m_handlers.push_back(suspendResume->registerEventHandler(thenFunc));
+ m_state->m_promise =
+ m_state->m_promise.call<emscripten::val>(
+ "then",
+ suspendResume->jsEventHandlerAt(
+ m_state->m_handlers.back()));
+
+ addFinallyFunction([](){}); // Add a potential cleanup handler
+ return (*this);
+}
+
+Promise& Promise::addCatchFunction(std::function<void(emscripten::val)> catchFunc)
+{
+ QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get();
+ Q_ASSERT(suspendResume);
+
+ m_state->m_handlers.push_back(suspendResume->registerEventHandler(catchFunc));
+ m_state->m_promise =
+ m_state->m_promise.call<emscripten::val>(
+ "catch",
+ suspendResume->jsEventHandlerAt(
+ m_state->m_handlers.back()));
+
+ addFinallyFunction([](){}); // Add a potential cleanup handler
+ return (*this);
+}
+
+Promise& Promise::addFinallyFunction(std::function<void()> finallyFunc)
+{
+ QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get();
+ Q_ASSERT(suspendResume);
+
+ auto thisHandler = std::make_shared<uint32_t>((uint32_t)(-1));
+ auto state = m_state;
+
+ std::function<void(emscripten::val)> func =
+ [state, thisHandler, finallyFunc](emscripten::val element) {
+ Q_UNUSED(element);
+
+ finallyFunc();
+
+ // See comment at top, we can only do the cleanup
+ // if we are the last handler in the handler chain
+ if (state->m_handlers.back() == *thisHandler) {
+ auto guard = state; // removeEventHandler will remove also this function
+ QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get();
+ Q_ASSERT(suspendResume);
+ for (int i = 0; i < guard->m_handlers.size(); ++i) {
+ suspendResume->removeEventHandler(guard->m_handlers[i]);
+ guard->m_handlers[i] = (uint32_t)(-1);
+ }
+ }
+ };
+
+ *thisHandler = suspendResume->registerEventHandler(func);
+ m_state->m_handlers.push_back(*thisHandler);
+ m_state->m_promise =
+ m_state->m_promise.call<emscripten::val>(
+ "finally",
+ suspendResume->jsEventHandlerAt(
+ m_state->m_handlers.back()));
+
+ return (*this);
+}
+
+void Promise::suspendExclusive()
+{
+ Promise::suspendExclusive(m_state->m_handlers);
+}
+
+emscripten::val Promise::getPromise() const
+{
+ return m_state->m_promise;
+}
+
uint32_t Promise::adoptPromise(emscripten::val promise, PromiseCallbacks callbacks, QList<uint32_t> *handlers)
{
Q_ASSERT_X(!!callbacks.catchFunc || !!callbacks.finallyFunc || !!callbacks.thenFunc,
diff --git a/src/corelib/platform/wasm/qstdweb_p.h b/src/corelib/platform/wasm/qstdweb_p.h
index b14d9e4012f..07df021c444 100644
--- a/src/corelib/platform/wasm/qstdweb_p.h
+++ b/src/corelib/platform/wasm/qstdweb_p.h
@@ -237,11 +237,80 @@ namespace qstdweb {
std::function<void()> finallyFunc;
};
- namespace Promise {
- uint32_t Q_CORE_EXPORT adoptPromise(emscripten::val promise, PromiseCallbacks callbacks, QList<uint32_t> *handlers = nullptr);
+ // Note: it is ok for the Promise object to go out of scope,
+ // the resources will be cleaned up in the finally handler.
+ class Q_CORE_EXPORT Promise {
+ public:
+ template<typename... Args>
+ Promise(emscripten::val target, QString methodName, Args... args) {
+ m_state = std::make_shared<State>();
+ m_state->m_promise = target.call<emscripten::val>(
+ methodName.toStdString().c_str(), std::forward<Args>(args)...);
+ if (m_state->m_promise.isUndefined() || m_state->m_promise["constructor"]["name"].as<std::string>() != "Promise") {
+ qFatal("This function did not return a promise");
+ }
+ addFinallyFunction([](){});
+ }
+
+ Promise(emscripten::val promise) {
+ m_state = std::make_shared<State>();
+ m_state->m_promise = promise;
+ if (m_state->m_promise.isUndefined() || m_state->m_promise["constructor"]["name"].as<std::string>() != "Promise") {
+ qFatal("This function did not return a promise");
+ }
+ addFinallyFunction([](){});
+ }
+
+ Promise(const std::vector<Promise> &promises) {
+ std::vector<emscripten::val> all;
+ all.reserve(promises.size());
+ for (const auto &p : promises)
+ all.push_back(p.getPromise());
+
+ auto arr = emscripten::val::array(all);
+ m_state = std::make_shared<State>();
+ m_state->m_promise = emscripten::val::global("Promise").call<emscripten::val>("all", arr);
+ addFinallyFunction([](){});
+ }
+
+ Promise& addThenFunction(std::function<void(emscripten::val)> thenFunc);
+ Promise& addCatchFunction(std::function<void(emscripten::val)> catchFunc);
+ Promise& addFinallyFunction(std::function<void()> finallyFunc);
+
+ void suspendExclusive();
+
+ emscripten::val getPromise() const;
+
+ public:
+ class State {
+ private:
+ friend class Promise;
+
+ State(const State&) = delete;
+ State(State&&) = delete;
+ State& operator=(const State&) = delete;
+ State& operator=(State&&) = delete;
+
+ public:
+ State() { ++s_numInstances; }
+ ~State() { --s_numInstances; }
+ static size_t numInstances() { return s_numInstances; }
+
+ private:
+ emscripten::val m_promise = emscripten::val::undefined();
+ QList<uint32_t> m_handlers;
+ static size_t s_numInstances;
+ };
+
+ private:
+ std::shared_ptr<State> m_state;
+
+ public:
+ // Deprecated: To be backwards compatible
+ static uint32_t Q_CORE_EXPORT adoptPromise(emscripten::val promise, PromiseCallbacks callbacks, QList<uint32_t> *handlers = nullptr);
template<typename... Args>
- uint32_t make(emscripten::val target,
+ static uint32_t make(emscripten::val target,
QString methodName,
PromiseCallbacks callbacks,
Args... args)
@@ -256,7 +325,7 @@ namespace qstdweb {
}
template<typename... Args>
- void make(
+ static void make(
QList<uint32_t> &handlers,
emscripten::val target,
QString methodName,
@@ -272,8 +341,8 @@ namespace qstdweb {
adoptPromise(std::move(promiseObject), std::move(callbacks), &handlers);
}
- void Q_CORE_EXPORT suspendExclusive(QList<uint32_t> handlerIndices);
- void Q_CORE_EXPORT all(std::vector<emscripten::val> promises, PromiseCallbacks callbacks);
+ static void Q_CORE_EXPORT suspendExclusive(QList<uint32_t> handlerIndices);
+ static void Q_CORE_EXPORT all(std::vector<emscripten::val> promises, PromiseCallbacks callbacks);
};
template<class F>