summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/networkinformation/android/jar/build.gradle4
-rw-r--r--src/plugins/platforms/android/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/android/androidbackendregister.cpp52
-rw-r--r--src/plugins/platforms/android/androidbackendregister.h67
-rw-r--r--src/plugins/platforms/android/androidcontentfileengine.cpp16
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp6
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp131
-rw-r--r--src/plugins/platforms/android/androidjniinput.h20
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp78
-rw-r--r--src/plugins/platforms/android/androidjnimain.h6
-rw-r--r--src/plugins/platforms/android/androidjnimenu.cpp18
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp20
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.cpp13
-rw-r--r--src/plugins/platforms/cocoa/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm17
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm46
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm19
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm13
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h8
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm94
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm4
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm40
-rw-r--r--src/plugins/platforms/cocoa/qnsview_gestures.mm3
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm3
-rw-r--r--src/plugins/platforms/direct2d/CMakeLists.txt1
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp4
-rw-r--r--src/plugins/platforms/eglfs/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp4
-rw-r--r--src/plugins/platforms/ios/CMakeLists.txt19
-rw-r--r--src/plugins/platforms/ios/SwiftIntegration.cmake78
-rw-r--r--src/plugins/platforms/ios/module.modulemap4
-rw-r--r--src/plugins/platforms/ios/qiosapplication.swift198
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.h5
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h2
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm21
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm20
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h31
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm50
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm5
-rw-r--r--src/plugins/platforms/ios/qioswindow.h3
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm43
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.mm13
-rw-r--r--src/plugins/platforms/ios/quiview.mm57
-rw-r--r--src/plugins/platforms/linuxfb/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/minimal/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/minimalegl/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/offscreen/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/qnx/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp16
-rw-r--r--src/plugins/platforms/qnx/qqnxkeytranslator.h2
-rw-r--r--src/plugins/platforms/vkkhrdisplay/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/vnc/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt4
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.cpp4
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.cpp11
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.cpp2
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.h1
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp7
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html5
-rw-r--r--src/plugins/platforms/windows/CMakeLists.txt5
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp61
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp12
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp1
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h7
-rw-r--r--src/plugins/platforms/windows/qwindowsmimeregistry.cpp18
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp653
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.h115
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp13
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h1
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h1
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp11
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h2
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp133
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h6
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp8
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h11
-rw-r--r--src/plugins/platforms/xcb/CMakeLists.txt6
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp27
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.h6
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp20
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp5
-rw-r--r--src/plugins/sqldrivers/.cmake.conf2
-rw-r--r--src/plugins/sqldrivers/ibase/qsql_ibase.cpp402
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc.cpp2
-rw-r--r--src/plugins/sqldrivers/sqlite/CMakeLists.txt2
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm6
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp38
104 files changed, 1493 insertions, 1455 deletions
diff --git a/src/plugins/networkinformation/android/jar/build.gradle b/src/plugins/networkinformation/android/jar/build.gradle
index 68a9381ad2..ea6d06c257 100644
--- a/src/plugins/networkinformation/android/jar/build.gradle
+++ b/src/plugins/networkinformation/android/jar/build.gradle
@@ -7,7 +7,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:8.0.2'
+ classpath 'com.android.tools.build:gradle:8.4.0'
}
}
@@ -26,7 +26,7 @@ android {
compileSdk 34
defaultConfig {
- minSdkVersion 23
+ minSdkVersion 28
}
sourceSets {
diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt
index d5a275a76c..aaf62dd7e7 100644
--- a/src/plugins/platforms/android/CMakeLists.txt
+++ b/src/plugins/platforms/android/CMakeLists.txt
@@ -9,7 +9,7 @@ qt_find_package(EGL)
qt_internal_add_plugin(QAndroidIntegrationPlugin
OUTPUT_NAME qtforandroid
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES android
+ DEFAULT_IF "android" IN_LIST QT_QPA_PLATFORMS
SOURCES
androidcontentfileengine.cpp androidcontentfileengine.h
androiddeadlockprotector.h
@@ -41,6 +41,7 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin
qandroidplatformwindow.cpp qandroidplatformwindow.h
qandroidsystemlocale.cpp qandroidsystemlocale.h
androidwindowembedding.cpp androidwindowembedding.h
+ androidbackendregister.cpp androidbackendregister.h
NO_UNITY_BUILD_SOURCES
# Conflicting symbols and macros with androidjnimain.cpp
# TODO: Unify the usage of FIND_AND_CHECK_CLASS, and similar
diff --git a/src/plugins/platforms/android/androidbackendregister.cpp b/src/plugins/platforms/android/androidbackendregister.cpp
new file mode 100644
index 0000000000..bfd86138aa
--- /dev/null
+++ b/src/plugins/platforms/android/androidbackendregister.cpp
@@ -0,0 +1,52 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "androidbackendregister.h"
+
+#include "androidjnimain.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcAndroidBackendRegister, "qt.qpa.androidbackendregister")
+
+Q_DECLARE_JNI_CLASS(BackendRegister, "org/qtproject/qt/android/BackendRegister");
+
+bool AndroidBackendRegister::registerNatives()
+{
+ return QtJniTypes::BackendRegister::registerNativeMethods(
+ { Q_JNI_NATIVE_SCOPED_METHOD(registerBackend, AndroidBackendRegister),
+ Q_JNI_NATIVE_SCOPED_METHOD(unregisterBackend, AndroidBackendRegister) });
+}
+
+void AndroidBackendRegister::registerBackend(JNIEnv *, jclass, jclass interfaceClass,
+ jobject interface)
+{
+ if (AndroidBackendRegister *reg = QtAndroid::backendRegister()) {
+ const QJniObject classObject(static_cast<jobject>(interfaceClass));
+ QString name = classObject.callMethod<jstring>("getName").toString();
+ name.replace('.', '/');
+
+ QMutexLocker lock(&reg->m_registerMutex);
+ reg->m_register[name] = QJniObject(interface);
+ } else {
+ qCWarning(lcAndroidBackendRegister)
+ << "AndroidBackendRegister pointer is null, cannot register functionality";
+ }
+}
+
+void AndroidBackendRegister::unregisterBackend(JNIEnv *, jclass, jclass interfaceClass)
+{
+ if (AndroidBackendRegister *reg = QtAndroid::backendRegister()) {
+ const QJniObject classObject(static_cast<jobject>(interfaceClass));
+ QString name = classObject.callMethod<jstring>("getName").toString();
+ name.replace('.', '/');
+
+ QMutexLocker lock(&reg->m_registerMutex);
+ reg->m_register.remove(name);
+ } else {
+ qCWarning(lcAndroidBackendRegister)
+ << "AndroidBackendRegister pointer is null, cannot unregister functionality";
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidbackendregister.h b/src/plugins/platforms/android/androidbackendregister.h
new file mode 100644
index 0000000000..c186f7e107
--- /dev/null
+++ b/src/plugins/platforms/android/androidbackendregister.h
@@ -0,0 +1,67 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef ANDROIDBACKENDREGISTER_H
+#define ANDROIDBACKENDREGISTER_H
+
+#include <type_traits>
+
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+#include <QtCore/qjniobject.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcAndroidBackendRegister)
+
+template <typename T>
+using ValidInterfaceType = std::enable_if_t<std::is_base_of_v<QtJniTypes::JObjectBase, T>, bool>;
+
+class AndroidBackendRegister
+{
+public:
+ static bool registerNatives();
+
+ template <typename T, ValidInterfaceType<T> = true>
+ [[nodiscard]] T getInterface()
+ {
+ QMutexLocker lock(&m_registerMutex);
+ return m_register.value(QString(QtJniTypes::Traits<T>::className().data()));
+ }
+
+ template <typename Object>
+ using IsObjectType =
+ typename std::disjunction<std::is_base_of<QJniObject, Object>,
+ std::is_base_of<QtJniTypes::JObjectBase, Object>>;
+
+ template <typename Interface, typename Ret, typename... Args,
+ ValidInterfaceType<Interface> = true>
+ auto callInterface(const char *func, Args... args)
+ {
+ if (const auto obj = getInterface<Interface>(); obj.isValid())
+ return obj.template callMethod<Ret, Args...>(func, std::forward<Args>(args)...);
+
+ if constexpr (IsObjectType<Ret>::value)
+ return Ret(QJniObject());
+ if constexpr (!std::is_same_v<Ret, void>)
+ return Ret{};
+ }
+
+private:
+ QMutex m_registerMutex;
+ QMap<QString, QJniObject> m_register;
+
+ static void registerBackend(JNIEnv *, jclass, jclass interfaceClass, jobject interface);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(registerBackend)
+ static void unregisterBackend(JNIEnv *, jclass, jclass interfaceClass);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(unregisterBackend)
+};
+
+QT_END_NAMESPACE
+
+#endif // ANDROIDBACKENDREGISTER_H
diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp
index db6c601f33..5757f5d8cc 100644
--- a/src/plugins/platforms/android/androidcontentfileengine.cpp
+++ b/src/plugins/platforms/android/androidcontentfileengine.cpp
@@ -21,7 +21,6 @@ Q_DECLARE_JNI_CLASS(UriType, "android/net/Uri");
Q_DECLARE_JNI_CLASS(Uri, "android/net/Uri");
Q_DECLARE_JNI_CLASS(ParcelFileDescriptorType, "android/os/ParcelFileDescriptor");
Q_DECLARE_JNI_CLASS(CursorType, "android/database/Cursor");
-Q_DECLARE_JNI_TYPE(StringArray, "[Ljava/lang/String;");
static QJniObject &contentResolverInstance()
{
@@ -375,11 +374,9 @@ public:
auto cursor = contentResolverInstance().callMethod<QtJniTypes::CursorType>(
"query",
uri.object<QtJniTypes::UriType>(),
- projection.isEmpty() ?
- nullptr : fromStringList(projection).object<QtJniTypes::StringArray>(),
+ QJniArray(projection),
selection.isEmpty() ? nullptr : QJniObject::fromString(selection).object<jstring>(),
- selectionArgs.isEmpty() ?
- nullptr : fromStringList(selectionArgs).object<QtJniTypes::StringArray>(),
+ QJniArray(selectionArgs),
sortOrder.isEmpty() ? nullptr : QJniObject::fromString(sortOrder).object<jstring>());
if (!cursor.isValid())
return {};
@@ -413,15 +410,6 @@ public:
bool moveToNext() { return m_object.callMethod<jboolean>("moveToNext"); }
private:
- static QJniObject fromStringList(const QStringList &list)
- {
- QJniEnvironment env;
- auto array = env->NewObjectArray(list.size(), env.findClass("java/lang/String"), nullptr);
- for (int i = 0; i < list.size(); ++i)
- env->SetObjectArrayElement(array, i, QJniObject::fromString(list[i]).object());
- return QJniObject::fromLocalRef(array);
- }
-
QJniObject m_object;
};
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index da5b63ef21..2010a9e03b 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -82,7 +82,7 @@ namespace QtAndroidAccessibility
void initialize()
{
- QtAndroid::qtActivityDelegate().callMethod<void>("initializeAccessibility");
+ QtAndroid::initializeAccessibility();
}
bool isActive()
@@ -470,6 +470,7 @@ namespace QtAndroidAccessibility
QAccessible::Role role;
QStringList actions;
QString description;
+ QString identifier;
bool hasTextSelection = false;
int selectionStart = 0;
int selectionEnd = 0;
@@ -485,6 +486,7 @@ namespace QtAndroidAccessibility
info.role = iface->role();
info.actions = QAccessibleBridgeUtils::effectiveActionNames(iface);
info.description = descriptionForInterface(iface);
+ info.identifier = QAccessibleBridgeUtils::accessibleId(iface);
QAccessibleTextInterface *textIface = iface->textInterface();
if (textIface && (textIface->selectionCount() > 0)) {
info.hasTextSelection = true;
@@ -550,6 +552,8 @@ namespace QtAndroidAccessibility
//CALL_METHOD(node, "setText", "(Ljava/lang/CharSequence;)V", jdesc)
env->CallVoidMethod(node, m_setContentDescriptionMethodID, jdesc);
+ QJniObject(node).callMethod<void>("setViewIdResourceName", info.identifier);
+
return true;
}
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index d074e73b9e..2692488ec6 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -24,6 +24,8 @@ Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
using namespace QtAndroid;
Q_DECLARE_JNI_CLASS(QtLayout, "org/qtproject/qt/android/QtLayout")
+Q_DECLARE_JNI_CLASS(QtLayoutInterface, "org/qtproject/qt/android/QtLayoutInterface")
+Q_DECLARE_JNI_CLASS(QtInputInterface, "org/qtproject/qt/android/QtInputInterface")
namespace QtAndroidInput
{
@@ -36,110 +38,50 @@ namespace QtAndroidInput
static QPointer<QWindow> m_mouseGrabber;
- GenericMotionEventListener::~GenericMotionEventListener() {}
- namespace {
- struct GenericMotionEventListeners {
- QMutex mutex;
- QList<QtAndroidInput::GenericMotionEventListener *> listeners;
- };
- }
- Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
-
- static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
- {
- jboolean ret = JNI_FALSE;
- QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
- for (auto *listener : std::as_const(g_genericMotionEventListeners()->listeners))
- ret |= listener->handleGenericMotionEvent(event);
- return ret;
- }
-
- KeyEventListener::~KeyEventListener() {}
- namespace {
- struct KeyEventListeners {
- QMutex mutex;
- QList<QtAndroidInput::KeyEventListener *> listeners;
- };
- }
- Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners)
-
- static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event)
- {
- jboolean ret = JNI_FALSE;
- QMutexLocker locker(&g_keyEventListeners()->mutex);
- for (auto *listener : std::as_const(g_keyEventListeners()->listeners))
- ret |= listener->handleKeyEvent(event);
- return ret;
- }
-
- void registerGenericMotionEventListener(QtAndroidInput::GenericMotionEventListener *listener)
- {
- QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
- g_genericMotionEventListeners()->listeners.push_back(listener);
- }
-
- void unregisterGenericMotionEventListener(QtAndroidInput::GenericMotionEventListener *listener)
- {
- QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
- g_genericMotionEventListeners()->listeners.removeOne(listener);
- }
-
- void registerKeyEventListener(QtAndroidInput::KeyEventListener *listener)
- {
- QMutexLocker locker(&g_keyEventListeners()->mutex);
- g_keyEventListeners()->listeners.push_back(listener);
- }
-
- void unregisterKeyEventListener(QtAndroidInput::KeyEventListener *listener)
- {
- QMutexLocker locker(&g_keyEventListeners()->mutex);
- g_keyEventListeners()->listeners.removeOne(listener);
- }
-
QJniObject qtLayout()
{
- return qtActivityDelegate().callMethod<QtJniTypes::QtLayout>("getQtLayout");
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ return reg->callInterface<QtJniTypes::QtLayoutInterface, QtJniTypes::QtLayout>(
+ "getQtLayout");
}
void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
{
qCDebug(lcQpaInputMethods) << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
- qtInputDelegate().callMethod<void>("updateSelection",
- selStart,
- selEnd,
- candidatesStart,
- candidatesEnd);
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtInputInterface, void>("updateSelection", selStart, selEnd,
+ candidatesStart, candidatesEnd);
}
void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType)
{
- qtInputDelegate().callMethod<void>("showSoftwareKeyboard",
- QtAndroidPrivate::activity(),
- qtLayout().object<QtJniTypes::QtLayout>(),
- left,
- top,
- width,
- height,
- inputHints,
- enterKeyType);
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtInputInterface, void>(
+ "showSoftwareKeyboard", QtAndroidPrivate::activity(),
+ qtLayout().object<QtJniTypes::QtLayout>(), left, top, width, height, inputHints,
+ enterKeyType);
qCDebug(lcQpaInputMethods) << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
}
void resetSoftwareKeyboard()
{
- qtInputDelegate().callMethod<void>("resetSoftwareKeyboard");
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtInputInterface, void>("resetSoftwareKeyboard");
qCDebug(lcQpaInputMethods) << "@@@ RESETSOFTWAREKEYBOARD";
}
void hideSoftwareKeyboard()
{
- qtInputDelegate().callMethod<void>("hideSoftwareKeyboard");
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtInputInterface, void>("hideSoftwareKeyboard");
qCDebug(lcQpaInputMethods) << "@@@ HIDESOFTWAREKEYBOARD";
}
bool isSoftwareKeyboardVisible()
{
- return qtInputDelegate().callMethod<jboolean>("isSoftwareKeyboardVisible");
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ return reg->callInterface<QtJniTypes::QtInputInterface, jboolean>(
+ "isSoftwareKeyboardVisible");
}
QRect softwareKeyboardRect()
@@ -149,17 +91,17 @@ namespace QtAndroidInput
int getSelectHandleWidth()
{
- return qtInputDelegate().callMethod<jint>("getSelectHandleWidth");
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ return reg->callInterface<QtJniTypes::QtInputInterface, jint>("getSelectHandleWidth");
}
void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
{
- qtInputDelegate().callMethod<void>("updateHandles",
- QtAndroidPrivate::activity(),
- qtLayout().object<QtJniTypes::QtLayout>(),
- mode, editMenuPos.x(), editMenuPos.y(), editButtons,
- cursor.x(), cursor.y(),
- anchor.x(), anchor.y(), rtl);
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtInputInterface, void>(
+ "updateHandles", QtAndroidPrivate::activity(),
+ qtLayout().object<QtJniTypes::QtLayout>(), mode, editMenuPos.x(), editMenuPos.y(),
+ editButtons, cursor.x(), cursor.y(), anchor.x(), anchor.y(), rtl);
}
// from https://developer.android.com/reference/android/view/MotionEvent#getButtonState()
@@ -324,7 +266,7 @@ namespace QtAndroidInput
m_touchPoints.clear();
}
- static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y,
+ static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint id, jint action, jboolean /*primary*/, jint x, jint y,
jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
{
QEventPoint::State state = QEventPoint::State::Stationary;
@@ -345,16 +287,25 @@ namespace QtAndroidInput
const int dw = availableWidthPixels();
const int dh = availableHeightPixels();
+ QWindow *window = QtAndroid::windowFromId(winId);
+ if (!window) {
+ qCWarning(lcQpaInputMethods, "Touch event received for non-existing window %d", winId);
+ return;
+ }
+
+ QPointF mappedTouchPoint = window->mapToGlobal(QPointF(x, y));
QWindowSystemInterface::TouchPoint touchPoint;
touchPoint.id = id;
touchPoint.pressure = pressure;
touchPoint.rotation = qRadiansToDegrees(rotation);
- touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
+ touchPoint.normalPosition = QPointF((mappedTouchPoint.x() / dw),
+ (mappedTouchPoint.y() / dh));
touchPoint.state = state;
- touchPoint.area = QRectF(x - double(minor * 0.5f),
- y - double(major * 0.5f),
+ touchPoint.area = QRectF(mappedTouchPoint.x() - double(minor * 0.5f),
+ mappedTouchPoint.y() - double(major * 0.5f),
double(minor),
double(major));
+
m_touchPoints.push_back(touchPoint);
if (state == QEventPoint::State::Pressed) {
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
@@ -976,8 +927,6 @@ namespace QtAndroidInput
{"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged},
{"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged},
{"handleLocationChanged", "(III)V", (void *)handleLocationChanged},
- {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
- {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
};
bool registerNatives(QJniEnvironment &env)
diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h
index 28a2665bf6..629b2937f0 100644
--- a/src/plugins/platforms/android/androidjniinput.h
+++ b/src/plugins/platforms/android/androidjniinput.h
@@ -31,26 +31,6 @@ namespace QtAndroidInput
QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
int getSelectHandleWidth();
- class GenericMotionEventListener
- {
- public:
- virtual ~GenericMotionEventListener();
- virtual bool handleGenericMotionEvent(jobject event) = 0;
- };
-
- class KeyEventListener
- {
- public:
- virtual ~KeyEventListener();
- virtual bool handleKeyEvent(jobject event) = 0;
- };
-
- void registerGenericMotionEventListener(GenericMotionEventListener *listener);
- void unregisterGenericMotionEventListener(GenericMotionEventListener *listener);
-
- void registerKeyEventListener(KeyEventListener *listener);
- void unregisterKeyEventListener(KeyEventListener *listener);
-
bool registerNatives(QJniEnvironment &env);
}
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 9fdcf3936b..5bd2b924fc 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -54,9 +54,6 @@ static jobject m_resourcesObj = nullptr;
static jclass m_qtActivityClass = nullptr;
static jclass m_qtServiceClass = nullptr;
-static QtJniTypes::QtActivityDelegateBase m_activityDelegate = nullptr;
-static QtJniTypes::QtInputDelegate m_inputDelegate = nullptr;
-
static int m_pendingApplicationState = -1;
static QBasicMutex m_platformMutex;
@@ -85,7 +82,7 @@ static double m_density = 1.0;
static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = nullptr;
static AndroidContentFileEngineHandler *m_androidContentFileEngineHandler = nullptr;
-
+static AndroidBackendRegister *m_backendRegister = nullptr;
static const char m_qtTag[] = "Qt";
static const char m_classErrorMsg[] = "Can't find class \"%s\"";
@@ -93,7 +90,8 @@ static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
Q_CONSTINIT static QBasicAtomicInt startQtAndroidPluginCalled = Q_BASIC_ATOMIC_INITIALIZER(0);
-Q_DECLARE_JNI_CLASS(QtEmbeddedDelegateFactory, "org/qtproject/qt/android/QtEmbeddedDelegateFactory")
+Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterface")
+Q_DECLARE_JNI_CLASS(QtAccessibilityInterface, "org/qtproject/qt/android/QtAccessibilityInterface");
namespace QtAndroid
{
@@ -184,36 +182,9 @@ namespace QtAndroid
// TODO move calls from here to where they logically belong
void setSystemUiVisibility(SystemUiVisibility uiVisibility)
{
- qtActivityDelegate().callMethod<void>("setSystemUiVisibility", jint(uiVisibility));
- }
-
- // FIXME: avoid direct access to QtActivityDelegate
- QtJniTypes::QtActivityDelegateBase qtActivityDelegate()
- {
- using namespace QtJniTypes;
- if (!m_activityDelegate.isValid()) {
- if (isQtApplication()) {
- auto context = QtAndroidPrivate::activity();
- m_activityDelegate = context.callMethod<QtActivityDelegateBase>("getActivityDelegate");
- } else {
- m_activityDelegate = QJniObject::callStaticMethod<QtActivityDelegateBase>(
- Traits<QtEmbeddedDelegateFactory>::className(),
- "getActivityDelegate",
- QtAndroidPrivate::activity());
- }
- }
-
- return m_activityDelegate;
- }
-
- QtJniTypes::QtInputDelegate qtInputDelegate()
- {
- if (!m_inputDelegate.isValid()) {
- m_inputDelegate = qtActivityDelegate().callMethod<QtJniTypes::QtInputDelegate>(
- "getInputDelegate");
- }
-
- return m_inputDelegate;
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtWindowInterface, void>("setSystemUiVisibility",
+ jint(uiVisibility));
}
bool isQtApplication()
@@ -234,36 +205,46 @@ namespace QtAndroid
return true;
}
+ void initializeAccessibility()
+ {
+ m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
+ "initializeAccessibility");
+ }
+
void notifyAccessibilityLocationChange(uint accessibilityObjectId)
{
- qtActivityDelegate().callMethod<void>("notifyLocationChange", accessibilityObjectId);
+ m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
+ "notifyLocationChange", accessibilityObjectId);
}
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
{
- qtActivityDelegate().callMethod<void>("notifyObjectHide",
- accessibilityObjectId, parentObjectId);
+ m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
+ "notifyObjectHide", accessibilityObjectId, parentObjectId);
}
void notifyObjectShow(uint parentObjectId)
{
- qtActivityDelegate().callMethod<void>("notifyObjectShow",
- parentObjectId);
+ m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
+ "notifyObjectShow", parentObjectId);
}
void notifyObjectFocus(uint accessibilityObjectId)
{
- qtActivityDelegate().callMethod<void>("notifyObjectFocus", accessibilityObjectId);
+ m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
+ "notifyObjectFocus", accessibilityObjectId);
}
void notifyValueChanged(uint accessibilityObjectId, jstring value)
{
- qtActivityDelegate().callMethod<void>("notifyValueChanged", accessibilityObjectId, value);
+ m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
+ "notifyValueChanged", accessibilityObjectId, value);
}
void notifyScrolledEvent(uint accessibilityObjectId)
{
- qtActivityDelegate().callMethod<void>("notifyScrolledEvent", accessibilityObjectId);
+ m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
+ "notifyScrolledEvent", accessibilityObjectId);
}
void notifyNativePluginIntegrationReady(bool ready)
@@ -387,6 +368,11 @@ namespace QtAndroid
return m_assets;
}
+ AndroidBackendRegister *backendRegister()
+ {
+ return m_backendRegister;
+ }
+
} // namespace QtAndroid
static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString)
@@ -397,6 +383,7 @@ static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring pa
m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler();
m_androidContentFileEngineHandler = new AndroidContentFileEngineHandler();
m_mainLibraryHnd = nullptr;
+ m_backendRegister = new AndroidBackendRegister();
const QStringList argsList = QProcess::splitCommand(QJniObject(paramsString).toString());
@@ -544,6 +531,8 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/)
m_androidPlatformIntegration = nullptr;
delete m_androidAssetsFileEngineHandler;
m_androidAssetsFileEngineHandler = nullptr;
+ delete m_backendRegister;
+ m_backendRegister = nullptr;
sem_post(&m_exitSemaphore);
}
@@ -891,7 +880,8 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
|| !QtAndroidDialogHelpers::registerNatives(env)
|| !QAndroidPlatformClipboard::registerNatives(env)
|| !QAndroidPlatformWindow::registerNatives(env)
- || !QtAndroidWindowEmbedding::registerNatives(env)) {
+ || !QtAndroidWindowEmbedding::registerNatives(env)
+ || !AndroidBackendRegister::registerNatives()) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h
index 99fff96d2b..9d616b18fb 100644
--- a/src/plugins/platforms/android/androidjnimain.h
+++ b/src/plugins/platforms/android/androidjnimain.h
@@ -13,6 +13,7 @@
#include <QImage>
#include <private/qjnihelpers_p.h>
#include <QtCore/QJniObject>
+#include <androidbackendregister.h>
QT_BEGIN_NAMESPACE
@@ -33,6 +34,7 @@ namespace QtAndroid
{
QBasicMutex *platformInterfaceMutex();
QAndroidPlatformIntegration *androidPlatformIntegration();
+ AndroidBackendRegister *backendRegister();
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration);
void setQtThread(QThread *thread);
void setViewVisibility(jobject view, bool visible);
@@ -48,9 +50,6 @@ namespace QtAndroid
AAssetManager *assetManager();
jclass applicationClass();
- QtJniTypes::QtActivityDelegateBase qtActivityDelegate();
- QtJniTypes::QtInputDelegate qtInputDelegate();
-
// Keep synchronized with flags in ActivityDelegate.java
enum SystemUiVisibility {
SYSTEM_UI_VISIBILITY_NORMAL = 0,
@@ -63,6 +62,7 @@ namespace QtAndroid
jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env);
jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = nullptr);
+ void initializeAccessibility();
void notifyAccessibilityLocationChange(uint accessibilityObjectId);
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId);
void notifyObjectShow(uint parentObjectId);
diff --git a/src/plugins/platforms/android/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp
index 8bf37d1af2..5f8a0b92e9 100644
--- a/src/plugins/platforms/android/androidjnimenu.cpp
+++ b/src/plugins/platforms/android/androidjnimenu.cpp
@@ -20,6 +20,8 @@ QT_BEGIN_NAMESPACE
using namespace QtAndroid;
+Q_DECLARE_JNI_CLASS(QtMenuInterface, "org/qtproject/qt/android/QtMenuInterface");
+
namespace QtAndroidMenu
{
static QList<QAndroidPlatformMenu *> pendingContextMenus;
@@ -44,12 +46,14 @@ namespace QtAndroidMenu
void resetMenuBar()
{
- qtActivityDelegate().callMethod<void>("resetOptionsMenu");
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtMenuInterface, void>("resetOptionsMenu");
}
void openOptionsMenu()
{
- qtActivityDelegate().callMethod<void>("openOptionsMenu");
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtMenuInterface, void>("openOptionsMenu");
}
void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect)
@@ -59,16 +63,18 @@ namespace QtAndroidMenu
pendingContextMenus.append(visibleMenu);
visibleMenu = menu;
menu->aboutToShow();
- qtActivityDelegate().callMethod<void>("openContextMenu",
- anchorRect.x(), anchorRect.y(),
- anchorRect.width(), anchorRect.height());
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtMenuInterface, void>("openContextMenu", anchorRect.x(),
+ anchorRect.y(), anchorRect.width(),
+ anchorRect.height());
}
void hideContextMenu(QAndroidPlatformMenu *menu)
{
QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu == menu) {
- qtActivityDelegate().callMethod<void>("closeContextMenu");
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtMenuInterface, void>("closeContextMenu");
pendingContextMenus.clear();
} else {
pendingContextMenus.removeOne(menu);
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index 9e20b7ac4b..4d752a3cc3 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -57,6 +57,7 @@ Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
Q_DECLARE_JNI_CLASS(Size, "android/util/Size")
Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative")
Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
+Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterface")
Q_DECLARE_JNI_CLASS(DisplayMode, "android/view/Display$Mode")
@@ -162,7 +163,10 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
return;
m_windowStack.prepend(window);
- QtAndroid::qtActivityDelegate().callMethod<void>("addTopLevelWindow", window->nativeWindow());
+
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtWindowInterface, void>("addTopLevelWindow",
+ window->nativeWindow());
if (window->window()->isVisible())
topVisibleWindowChanged();
@@ -175,7 +179,9 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
if (m_windowStack.contains(window))
qWarning() << "Failed to remove window";
- QtAndroid::qtActivityDelegate().callMethod<void>("removeTopLevelWindow", window->nativeViewId());
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtWindowInterface, void>("removeTopLevelWindow",
+ window->nativeViewId());
topVisibleWindowChanged();
}
@@ -187,7 +193,10 @@ void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window)
return;
if (index > 0) {
m_windowStack.move(index, 0);
- QtAndroid::qtActivityDelegate().callMethod<void>("bringChildToFront", window->nativeViewId());
+
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtWindowInterface, void>("bringChildToFront",
+ window->nativeViewId());
}
topVisibleWindowChanged();
}
@@ -198,7 +207,10 @@ void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window)
if (index == -1 || index == (m_windowStack.size() - 1))
return;
m_windowStack.move(index, m_windowStack.size() - 1);
- QtAndroid::qtActivityDelegate().callMethod<void>("bringChildToBack", window->nativeViewId());
+
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ reg->callInterface<QtJniTypes::QtWindowInterface, void>("bringChildToBack",
+ window->nativeViewId());
topVisibleWindowChanged();
}
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp
index 979f0fb98a..2482160573 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp
@@ -16,6 +16,10 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window")
+Q_DECLARE_JNI_CLASS(QtInputInterface, "org/qtproject/qt/android/QtInputInterface")
+Q_DECLARE_JNI_CLASS(QtInputConnectionListener,
+ "org/qtproject/qt/android/QtInputConnection$QtInputConnectionListener")
+
QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
: QPlatformWindow(window), m_nativeQtWindow(nullptr),
m_surfaceContainerType(SurfaceContainer::TextureView), m_nativeParentQtWindow(nullptr),
@@ -55,10 +59,13 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
m_nativeParentQtWindow = androidParent->nativeWindow();
}
+ AndroidBackendRegister *reg = QtAndroid::backendRegister();
+ QtJniTypes::QtInputConnectionListener listener =
+ reg->callInterface<QtJniTypes::QtInputInterface, QtJniTypes::QtInputConnectionListener>(
+ "getInputConnectionListener");
+
m_nativeQtWindow = QJniObject::construct<QtJniTypes::QtWindow>(
- QNativeInterface::QAndroidApplication::context(),
- m_nativeParentQtWindow,
- QtAndroid::qtInputDelegate());
+ QNativeInterface::QAndroidApplication::context(), m_nativeParentQtWindow, listener);
m_nativeViewId = m_nativeQtWindow.callMethod<jint>("getId");
if (window->isTopLevel())
diff --git a/src/plugins/platforms/cocoa/CMakeLists.txt b/src/plugins/platforms/cocoa/CMakeLists.txt
index 92e681d8fb..491c61703f 100644
--- a/src/plugins/platforms/cocoa/CMakeLists.txt
+++ b/src/plugins/platforms/cocoa/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QCocoaIntegrationPlugin
OUTPUT_NAME qcocoa
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES cocoa
+ DEFAULT_IF "cocoa" IN_LIST QT_QPA_PLATFORMS
PLUGIN_TYPE platforms
SOURCES
main.mm
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index c5e40a4087..40c1e90511 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -36,6 +36,23 @@ void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
}
switch (event->type()) {
+ case QAccessible::Announcement: {
+ auto *announcementEvent = static_cast<QAccessibleAnnouncementEvent *>(event);
+ auto priorityLevel = (announcementEvent->priority() == QAccessible::AnnouncementPriority::Assertive)
+ ? NSAccessibilityPriorityHigh
+ : NSAccessibilityPriorityMedium;
+ NSDictionary *announcementInfo = @{
+ NSAccessibilityPriorityKey: [NSNumber numberWithInt:priorityLevel],
+ NSAccessibilityAnnouncementKey: announcementEvent->message().toNSString()
+ };
+ // post event for application element, as the comment for
+ // NSAccessibilityAnnouncementRequestedNotification in the
+ // NSAccessibilityConstants.h header says
+ NSAccessibilityPostNotificationWithUserInfo(NSApp,
+ NSAccessibilityAnnouncementRequestedNotification,
+ announcementInfo);
+ break;
+ }
case QAccessible::Focus: {
NSAccessibilityPostNotification(element, NSAccessibilityFocusedUIElementChangedNotification);
break;
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 8d4d6d683d..b319dd072e 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -520,6 +520,12 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return nil;
}
+- (NSString*) accessibilityIdentifier {
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return QAccessibleBridgeUtils::accessibleId(iface).toNSString();
+ return nil;
+}
+
- (BOOL) isAccessibilityEnabled {
if (QAccessibleInterface *iface = self.qtInterface)
return !iface->state().disabled;
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index aaa35a91ef..99759424f9 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -134,24 +134,42 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
case Qt::DragLinkCursor:
cocoaCursor = [NSCursor dragLinkCursor];
break;
-#if !defined(QT_APPLE_NO_PRIVATE_APIS)
case Qt::SizeVerCursor:
- if ([NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)])
- cocoaCursor = [NSCursor _windowResizeNorthSouthCursor];
- break;
case Qt::SizeHorCursor:
- if ([NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)])
- cocoaCursor = [NSCursor _windowResizeEastWestCursor];
- break;
case Qt::SizeBDiagCursor:
- if ([NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)])
- cocoaCursor = [NSCursor _windowResizeNorthEastSouthWestCursor];
- break;
- case Qt::SizeFDiagCursor:
- if ([NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)])
- cocoaCursor = [NSCursor _windowResizeNorthWestSouthEastCursor];
- break;
+ case Qt::SizeFDiagCursor: {
+#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(150000)
+ if (@available(macOS 15, *)) {
+ auto position = [newShape]{
+ switch (newShape) {
+ case Qt::SizeVerCursor: return NSCursorFrameResizePositionTop;
+ case Qt::SizeHorCursor: return NSCursorFrameResizePositionLeft;
+ case Qt::SizeBDiagCursor: return NSCursorFrameResizePositionTopRight;
+ case Qt::SizeFDiagCursor: return NSCursorFrameResizePositionTopLeft;
+ default: Q_UNREACHABLE();
+ }
+ }();
+ cocoaCursor = [NSCursor frameResizeCursorFromPosition:position
+ inDirections:NSCursorFrameResizeDirectionsAll];
+ break;
+ }
+#endif // macOS 15 SDK
+#if !defined(QT_APPLE_NO_PRIVATE_APIS)
+ auto selector = [newShape]{
+ switch (newShape) {
+ case Qt::SizeVerCursor: return @selector(_windowResizeNorthSouthCursor);
+ case Qt::SizeHorCursor: return @selector(_windowResizeEastWestCursor);
+ case Qt::SizeBDiagCursor: return @selector(_windowResizeNorthEastSouthWestCursor);
+ case Qt::SizeFDiagCursor: return @selector(_windowResizeNorthWestSouthEastCursor);
+ default: Q_UNREACHABLE();
+ }
+ }();
+
+ if ([NSCursor respondsToSelector:selector])
+ cocoaCursor = [NSCursor performSelector:selector];
#endif // QT_APPLE_NO_PRIVATE_APIS
+ break;
+ }
default:
break;
}
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index a8404889e9..3a9f5a8794 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -9,7 +9,6 @@
#include "qcocoahelpers.h"
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/qutimimeconverter.h>
-#include <QtCore/qsysinfo.h>
#include <QtCore/private/qcore_mac_p.h>
#include <vector>
@@ -137,11 +136,6 @@ bool QCocoaDrag::maybeDragMultipleItems()
Q_ASSERT(m_drag && m_drag->mimeData());
Q_ASSERT(m_executed_drop_action == Qt::IgnoreAction);
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave) {
- // -dragImage: stopped working in 10.14 first.
- return false;
- }
-
const QMacAutoReleasePool pool;
NSView *view = m_lastView ? m_lastView : m_lastEvent.window.contentView;
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 044a282686..41170b74ea 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -14,8 +14,6 @@
#include <QtCore/qstringlist.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qabstracteventdispatcher.h>
-#include <QtCore/qsysinfo.h>
-#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qdir.h>
#include <QtCore/qregularexpression.h>
#include <QtCore/qpointer.h>
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index be562e5455..2249658189 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -471,25 +471,6 @@ void QCocoaScreen::deliverUpdateRequests()
if (!platformWindow->updatesWithDisplayLink())
continue;
- // QTBUG-107198: Skip updates in a live resize for a better resize experience.
- if (platformWindow->isContentView() && platformWindow->view().inLiveResize) {
- const QSurface::SurfaceType surfaceType = window->surfaceType();
- const bool usesMetalLayer = surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
- const bool usesNonDefaultContentsPlacement = [platformWindow->view() layerContentsPlacement]
- != NSViewLayerContentsPlacementScaleAxesIndependently;
- if (usesMetalLayer && usesNonDefaultContentsPlacement) {
- static bool deliverDisplayLinkUpdatesDuringLiveResize =
- qEnvironmentVariableIsSet("QT_MAC_DISPLAY_LINK_UPDATE_IN_RESIZE");
- if (!deliverDisplayLinkUpdatesDuringLiveResize) {
- // Must keep the link running, we do not know what the event
- // handlers for UpdateRequest (which is not sent now) would do,
- // would they trigger a new requestUpdate() or not.
- pauseUpdates = false;
- continue;
- }
- }
- }
-
platformWindow->deliverUpdateRequest();
// Another update request was triggered, keep the display link running
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index d9135c76c8..1623b12be6 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -5,7 +5,6 @@
#include "qcocoatheme.h"
-#include <QtCore/QOperatingSystemVersion>
#include <QtCore/QVariant>
#include "qcocoasystemtrayicon.h"
@@ -214,12 +213,10 @@ const char *QCocoaTheme::name = "cocoa";
QCocoaTheme::QCocoaTheme()
: m_systemPalette(nullptr)
{
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
- m_appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
- NSAppearance.currentAppearance = NSApp.effectiveAppearance;
- handleSystemThemeChange();
- });
- }
+ m_appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
+ NSAppearance.currentAppearance = NSApp.effectiveAppearance;
+ handleSystemThemeChange();
+ });
m_systemColorObserver = QMacNotificationObserver(nil,
NSSystemColorsDidChangeNotification, [this] {
@@ -467,6 +464,8 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
return NSEvent.keyRepeatDelay * 1000;
case QPlatformTheme::KeyboardAutoRepeatRate:
return 1.0 / NSEvent.keyRepeatInterval;
+ case QPlatformTheme::ShowIconsInMenus:
+ return false;
default:
break;
}
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index ba1bc052fb..2036d4bf4c 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -80,6 +80,8 @@ public:
QRect normalGeometry() const override;
void setCocoaGeometry(const QRect &rect);
+ QMargins safeAreaMargins() const override;
+
void setVisible(bool visible) override;
void setWindowFlags(Qt::WindowFlags flags) override;
void setWindowState(Qt::WindowStates state) override;
@@ -122,6 +124,7 @@ public:
Q_NOTIFICATION_HANDLER(NSWindowDidMoveNotification) void windowDidMove();
Q_NOTIFICATION_HANDLER(NSWindowDidResizeNotification) void windowDidResize();
+ Q_NOTIFICATION_HANDLER(NSWindowWillStartLiveResizeNotification) void windowWillStartLiveResize();
Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize();
Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey();
Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey();
@@ -186,6 +189,8 @@ public:
Q_DECLARE_FLAGS(RecreationReasons, RecreationReason)
Q_FLAG(RecreationReasons)
+ bool inLiveResize() const override;
+
protected:
void recreateWindowIfNeeded();
QCocoaNSWindow *createNSWindow(bool shouldBePanel);
@@ -232,6 +237,7 @@ public: // for QNSView
bool m_inSetVisible = false;
bool m_inSetGeometry = false;
bool m_inSetStyleMask = false;
+ bool m_inLiveResize = false;
QCocoaMenuBar *m_menubar = nullptr;
@@ -241,6 +247,8 @@ public: // for QNSView
int m_registerTouchCount = 0;
bool m_resizableTransientParent = false;
+ QMargins m_lastReportedSafeAreaMargins;
+
static const int NoAlertRequest;
NSInteger m_alertRequest = NoAlertRequest;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 4a245a0f8a..b4c8ae4ba1 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -24,6 +24,7 @@
#include <qpa/qplatformscreen.h>
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtGui/private/qmetallayer_p.h>
#include <QDebug>
@@ -285,6 +286,54 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
// will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm)
}
+QMargins QCocoaWindow::safeAreaMargins() const
+{
+ // The safe area of the view reflects the area not covered by navigation
+ // bars, tab bars, toolbars, and other ancestor views that might obscure
+ // the current view (by setting additionalSafeAreaInsets). If the window
+ // uses NSWindowStyleMaskFullSizeContentView this also includes the area
+ // of the view covered by the title bar.
+ QMarginsF viewSafeAreaMargins = {
+ m_view.safeAreaInsets.left,
+ m_view.safeAreaInsets.top,
+ m_view.safeAreaInsets.right,
+ m_view.safeAreaInsets.bottom
+ };
+
+ // The screen's safe area insets represent the distances from the screen's
+ // edges at which content isn't obscured. The view's safe area margins do
+ // not include the screen's insets automatically, so we need to manually
+ // merge them.
+ auto screenRect = m_view.window.screen.frame;
+ auto screenInsets = m_view.window.screen.safeAreaInsets;
+ auto screenRelativeViewBounds = QCocoaScreen::mapFromNative(
+ [m_view.window convertRectToScreen:
+ [m_view convertRect:m_view.bounds toView:nil]]
+ );
+
+ // The margins are relative to the screen the window is on.
+ // Note that we do not want represent the area outside of the
+ // screen as being outside of the safe area.
+ QMarginsF screenSafeAreaMargins = {
+ screenInsets.left ?
+ qMax(0.0f, screenInsets.left - screenRelativeViewBounds.left())
+ : 0.0f,
+ screenInsets.top ?
+ qMax(0.0f, screenInsets.top - screenRelativeViewBounds.top())
+ : 0.0f,
+ screenInsets.right ?
+ qMax(0.0f, screenInsets.right
+ - (screenRect.size.width - screenRelativeViewBounds.right()))
+ : 0.0f,
+ screenInsets.bottom ?
+ qMax(0.0f, screenInsets.bottom
+ - (screenRect.size.height - screenRelativeViewBounds.bottom()))
+ : 0.0f
+ };
+
+ return (screenSafeAreaMargins | viewSafeAreaMargins).toMargins();
+}
+
bool QCocoaWindow::startSystemMove()
{
switch (NSApp.currentEvent.type) {
@@ -514,7 +563,7 @@ NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags)
auto *nsWindow = transientCocoaWindow->nativeWindow();
// We only upgrade the window level for "special" windows, to work
- // around Qt Designer parenting the designer windows to the widget
+ // around Qt Widgets Designer parenting the designer windows to the widget
// palette window (QTBUG-31779). This should be fixed in designer.
if (type != Qt::Window)
windowLevel = qMax(windowLevel, nsWindow.level);
@@ -1236,8 +1285,26 @@ void QCocoaWindow::windowDidResize()
handleWindowStateChanged();
}
+void QCocoaWindow::windowWillStartLiveResize()
+{
+ // Track live resizing for all windows, including
+ // child windows, so we know if it's safe to update
+ // the window unthrottled outside of the main thread.
+ m_inLiveResize = true;
+}
+
+bool QCocoaWindow::inLiveResize() const
+{
+ // Use member variable to track this instead of reflecting
+ // NSView.inLiveResize directly, so it can be called from
+ // non-main threads.
+ return m_inLiveResize;
+}
+
void QCocoaWindow::windowDidEndLiveResize()
{
+ m_inLiveResize = false;
+
if (!isContentView())
return;
@@ -1435,6 +1502,12 @@ void QCocoaWindow::handleGeometryChange()
QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
+ // Changing the window geometry may affect the safe area margins
+ if (safeAreaMargins() != m_lastReportedSafeAreaMargins) {
+ m_lastReportedSafeAreaMargins = safeAreaMargins();
+ QWindowSystemInterface::handleSafeAreaMarginsChanged(window());
+ }
+
// Guard against processing window system events during QWindow::setGeometry
// calls, which Qt and Qt applications do not expect.
if (!m_inSetGeometry)
@@ -1617,6 +1690,23 @@ bool QCocoaWindow::updatesWithDisplayLink() const
void QCocoaWindow::deliverUpdateRequest()
{
qCDebug(lcQpaDrawing) << "Delivering update request to" << window();
+
+ if (auto *qtMetalLayer = qt_objc_cast<QMetalLayer*>(m_view.layer)) {
+ // We attempt a read lock here, so that the animation/render thread is
+ // prioritized lower than the main thread's displayLayer processing.
+ // Without this the two threads might fight over the next drawable,
+ // starving the main thread's presentation of the resized layer.
+ if (!qtMetalLayer.displayLock.tryLockForRead()) {
+ qCDebug(lcQpaDrawing) << "Deferring update request"
+ << "due to" << qtMetalLayer << "needing display";
+ return;
+ }
+
+ // But we don't hold the lock, as the update request can recurse
+ // back into setNeedsDisplay, which would deadlock.
+ qtMetalLayer.displayLock.unlock();
+ }
+
QPlatformWindow::deliverUpdateRequest();
}
@@ -1663,7 +1753,7 @@ void QCocoaWindow::setupPopupMonitor()
| NSEventMaskMouseMoved;
s_globalMouseMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:mouseButtonMask
handler:^(NSEvent *e){
- if (!QGuiApplicationPrivate::instance()->popupActive()) {
+ if (!QGuiApplicationPrivate::instance()->activePopupWindow()) {
removePopupMonitor();
return;
}
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 48ffa5c1cc..eb998b0409 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -21,7 +21,6 @@
#include <QtCore/QDebug>
#include <QtCore/QPointer>
#include <QtCore/QSet>
-#include <QtCore/qsysinfo.h>
#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/QAccessible>
#include <QtGui/QImage>
@@ -36,6 +35,9 @@
#endif
#include "qcocoaintegration.h"
#include <QtGui/private/qmacmimeregistry_p.h>
+#include <QtGui/private/qmetallayer_p.h>
+
+#include <QuartzCore/CATransaction.h>
@interface QNSView (Drawing) <CALayerDelegate>
- (void)initDrawing;
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
index bf102e43f8..61691ab4fb 100644
--- a/src/plugins/platforms/cocoa/qnsview_drawing.mm
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -75,7 +75,10 @@
// too late at this point and the QWindow will be non-functional,
// but we can at least print a warning.
if ([MTLCreateSystemDefaultDevice() autorelease]) {
- return [CAMetalLayer layer];
+ static bool allowPresentsWithTransaction =
+ !qEnvironmentVariableIsSet("QT_MTL_NO_TRANSACTION");
+ return allowPresentsWithTransaction ?
+ [QMetalLayer layer] : [CAMetalLayer layer];
} else {
qCWarning(lcQpaDrawing) << "Failed to create QWindow::MetalSurface."
<< "Metal is not supported by any of the GPUs in this system.";
@@ -222,8 +225,39 @@
return;
}
- qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
- m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect());
+ const auto handleExposeEvent = [&]{
+ const auto bounds = QRectF::fromCGRect(self.bounds).toRect();
+ qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window() << bounds;
+ m_platformWindow->handleExposeEvent(bounds);
+ };
+
+ if (auto *qtMetalLayer = qt_objc_cast<QMetalLayer*>(self.layer)) {
+ const bool presentedWithTransaction = qtMetalLayer.presentsWithTransaction;
+ qtMetalLayer.presentsWithTransaction = YES;
+
+ handleExposeEvent();
+
+ // If the expose event resulted in a secondary thread requesting that its
+ // drawable should be presented on the main thread with transaction, do so.
+ if (auto mainThreadPresentation = qtMetalLayer.mainThreadPresentation) {
+ mainThreadPresentation();
+ qtMetalLayer.mainThreadPresentation = nil;
+ }
+
+ qtMetalLayer.presentsWithTransaction = presentedWithTransaction;
+
+ // We're done presenting, but we must wait to unlock the display lock
+ // until the display cycle finishes, as otherwise the render thread may
+ // step in and present before the transaction commits. The display lock
+ // is recursive, so setNeedsDisplay can be safely called in the meantime
+ // without any issue.
+ QMetaObject::invokeMethod(m_platformWindow, [qtMetalLayer]{
+ qCDebug(lcMetalLayer) << "Unlocking" << qtMetalLayer << "after finishing display-cycle";
+ qtMetalLayer.displayLock.unlock();
+ }, Qt::QueuedConnection);
+ } else {
+ handleExposeEvent();
+ }
}
@end
diff --git a/src/plugins/platforms/cocoa/qnsview_gestures.mm b/src/plugins/platforms/cocoa/qnsview_gestures.mm
index 7c64e3356f..9c5ead072b 100644
--- a/src/plugins/platforms/cocoa/qnsview_gestures.mm
+++ b/src/plugins/platforms/cocoa/qnsview_gestures.mm
@@ -11,9 +11,6 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
- (bool)handleGestureAsBeginEnd:(NSEvent *)event
{
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXElCapitan)
- return false;
-
if ([event phase] == NSEventPhaseBegan) {
[self beginGestureWithEvent:event];
return true;
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index 74ba6f65ac..f536045fec 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -12,7 +12,6 @@
#include "qcocoaintegration.h"
#include <qpa/qwindowsysteminterface.h>
-#include <qoperatingsystemversion.h>
Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events");
@@ -351,7 +350,7 @@ NSWindow<QNSWindowProtocol> *qnswindow_cast(NSWindow *window)
// not Qt). However, an active popup is expected to grab any mouse event within the
// application, so we need to handle those explicitly and trust Qt's isWindowBlocked
// implementation to eat events that shouldn't be delivered anyway.
- if (isMouseEvent(theEvent) && QGuiApplicationPrivate::instance()->popupActive()
+ if (isMouseEvent(theEvent) && QGuiApplicationPrivate::instance()->activePopupWindow()
&& QGuiApplicationPrivate::instance()->isWindowBlocked(m_platformWindow->window(), nullptr)) {
qCDebug(lcQpaWindow) << "Mouse event over modally blocked window" << m_platformWindow->window()
<< "while popup is open - redirecting";
diff --git a/src/plugins/platforms/direct2d/CMakeLists.txt b/src/plugins/platforms/direct2d/CMakeLists.txt
index 54e96b09e5..062dc30143 100644
--- a/src/plugins/platforms/direct2d/CMakeLists.txt
+++ b/src/plugins/platforms/direct2d/CMakeLists.txt
@@ -23,7 +23,6 @@ qt_internal_add_plugin(QWindowsDirect2DIntegrationPlugin
../windows/qwindowskeymapper.cpp ../windows/qwindowskeymapper.h
../windows/qwindowsmenu.cpp ../windows/qwindowsmenu.h
../windows/qwindowsmimeregistry.cpp ../windows/qwindowsmimeregistry.h
- ../windows/qwindowsmousehandler.cpp ../windows/qwindowsmousehandler.h
../windows/qwindowsnativeinterface.cpp ../windows/qwindowsnativeinterface.h
../windows/qwindowsole.cpp ../windows/qwindowsole.h
../windows/qwindowsopengltester.cpp ../windows/qwindowsopengltester.h
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
index 2866c68de2..71a59cb08f 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
@@ -84,10 +84,12 @@ QT_WARNING_POP
case QPaintDevice::PdmDevicePixelRatio:
return 1;
case QPaintDevice::PdmDevicePixelRatioScaled:
- return qRound(devicePixelRatioFScale());
+ return int(devicePixelRatioFScale());
case QPaintDevice::PdmWidthMM:
case QPaintDevice::PdmHeightMM:
break;
+ default:
+ break;
}
return -1;
diff --git a/src/plugins/platforms/eglfs/CMakeLists.txt b/src/plugins/platforms/eglfs/CMakeLists.txt
index a0a6116a45..cb4b5d1eb9 100644
--- a/src/plugins/platforms/eglfs/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/CMakeLists.txt
@@ -92,7 +92,7 @@ endif()
qt_internal_add_plugin(QEglFSIntegrationPlugin
OUTPUT_NAME qeglfs
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES eglfs
+ DEFAULT_IF "eglfs" IN_LIST QT_QPA_PLATFORMS
SOURCES
qeglfsmain.cpp
DEFINES
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
index d171715e72..87990ad592 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp
@@ -7,6 +7,8 @@
#include "qeglfskmsgbmscreen_p.h"
#include "qeglfskmsgbmdevice_p.h"
+#include <private/qeglfskmsintegration_p.h>
+
#include <QtCore/QFile>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
@@ -30,8 +32,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
QEglFSKmsGbmCursor::QEglFSKmsGbmCursor(QEglFSKmsGbmScreen *screen)
: m_screen(screen)
, m_cursorSize(64, 64) // 64x64 is the old standard size, we now try to query the real size below
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
index 89479fc250..a7592ed55e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
@@ -7,6 +7,7 @@
#include "qeglfskmsgbmscreen_p.h"
#include <private/qeglfsintegration_p.h>
+#include <private/qeglfskmsintegration_p.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/private/qcore_unix_p.h>
@@ -15,8 +16,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
QEglFSKmsGbmDevice::QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path)
: QEglFSKmsDevice(screenConfig, path)
, m_gbm_device(nullptr)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 8dcfed04db..e2a806f491 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -6,7 +6,9 @@
#include "qeglfskmsgbmscreen_p.h"
#include "qeglfskmsgbmdevice_p.h"
#include "qeglfskmsgbmcursor_p.h"
+
#include <private/qeglfsintegration_p.h>
+#include <private/qeglfskmsintegration_p.h>
#include <QtCore/QLoggingCategory>
@@ -18,8 +20,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
QMutex QEglFSKmsGbmScreen::m_nonThreadedFlipMutex;
static inline uint32_t drmFormatToGbmFormat(uint32_t drmFormat)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
index 3fc46cd224..5af45e63a2 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
@@ -3,14 +3,15 @@
#include "qeglfskmsegldevicescreen.h"
#include "qeglfskmsegldevice.h"
+
+#include <private/qeglfskmsintegration_p.h>
+
#include <QGuiApplication>
#include <QLoggingCategory>
#include <errno.h>
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsDevice *device, const QKmsOutput &output)
: QEglFSKmsScreen(device, output)
, m_default_fb_handle(uint32_t(-1))
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
index 96cdcd8947..c0c9655496 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmseventreader.cpp
@@ -4,14 +4,14 @@
#include "qeglfskmseventreader_p.h"
#include "qeglfskmsdevice_p.h"
#include "qeglfskmsscreen_p.h"
+#include "qeglfskmsintegration_p.h"
+
#include <QSocketNotifier>
#include <QCoreApplication>
#include <QLoggingCategory>
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
static void pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
{
Q_UNUSED(fd);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h
index 36e65a0bd4..26da231092 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration_p.h
@@ -27,7 +27,7 @@ QT_BEGIN_NAMESPACE
class QKmsDevice;
class QKmsScreenConfig;
-Q_DECLARE_EXPORTED_LOGGING_CATEGORY(qLcEglfsKmsDebug, Q_EGLFS_EXPORT)
+QT_DECLARE_EXPORTED_QT_LOGGING_CATEGORY(qLcEglfsKmsDebug, Q_EGLFS_EXPORT)
class Q_EGLFS_EXPORT QEglFSKmsIntegration : public QEglFSDeviceIntegration
{
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
index 369356b761..cc7381fb70 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -5,7 +5,9 @@
#include "qeglfskmsscreen_p.h"
#include "qeglfskmsdevice_p.h"
+
#include <private/qeglfsintegration_p.h>
+#include <private/qeglfskmsintegration_p.h>
#include <QtCore/QLoggingCategory>
@@ -14,8 +16,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
class QEglFSKmsInterruptHandler : public QObject
{
public:
diff --git a/src/plugins/platforms/ios/CMakeLists.txt b/src/plugins/platforms/ios/CMakeLists.txt
index 4cc3efc91e..51c1b52cf3 100644
--- a/src/plugins/platforms/ios/CMakeLists.txt
+++ b/src/plugins/platforms/ios/CMakeLists.txt
@@ -5,10 +5,23 @@
## QIOSIntegrationPlugin Plugin:
#####################################################################
+if(VISIONOS)
+ include(SwiftIntegration.cmake)
+
+ qt_install(TARGETS QIOSIntegrationPluginSwift
+ EXPORT "${INSTALL_CMAKE_NAMESPACE}QIOSIntegrationPluginTargets"
+ DESTINATION "${INSTALL_LIBDIR}"
+ )
+ qt_internal_add_targets_to_additional_targets_export_file(
+ TARGETS QIOSIntegrationPluginSwift
+ EXPORT_NAME_PREFIX "${INSTALL_CMAKE_NAMESPACE}QIOSIntegrationPlugin"
+ )
+endif()
+
qt_internal_add_plugin(QIOSIntegrationPlugin
OUTPUT_NAME qios
STATIC # Force static, even in shared builds
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES ios
+ DEFAULT_IF "ios" IN_LIST QT_QPA_PLATFORMS
PLUGIN_TYPE platforms
SOURCES
plugin.mm
@@ -86,3 +99,7 @@ qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT (TVOS OR VISIONOS)
)
add_subdirectory(optional)
+
+if(VISIONOS)
+ target_link_libraries(QIOSIntegrationPlugin PRIVATE QIOSIntegrationPluginSwift)
+endif()
diff --git a/src/plugins/platforms/ios/SwiftIntegration.cmake b/src/plugins/platforms/ios/SwiftIntegration.cmake
new file mode 100644
index 0000000000..d52edb3ad2
--- /dev/null
+++ b/src/plugins/platforms/ios/SwiftIntegration.cmake
@@ -0,0 +1,78 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(CMAKE_Swift_COMPILER_TARGET arm64-apple-xros)
+if($CACHE{CMAKE_OSX_SYSROOT} MATCHES "^[a-z]+simulator$")
+ set(CMAKE_Swift_COMPILER_TARGET "${CMAKE_Swift_COMPILER_TARGET}-simulator")
+endif()
+
+cmake_policy(SET CMP0157 NEW)
+enable_language(Swift)
+
+# Verify that we have a new enough compiler
+if("${CMAKE_Swift_COMPILER_VERSION}" VERSION_LESS 5.9)
+ message(FATAL_ERROR "Swift 5.9 required for C++ interoperability")
+endif()
+
+get_target_property(QT_CORE_INCLUDES Qt6::Core INTERFACE_INCLUDE_DIRECTORIES)
+get_target_property(QT_GUI_INCLUDES Qt6::Gui INTERFACE_INCLUDE_DIRECTORIES)
+get_target_property(QT_CORE_PRIVATE_INCLUDES Qt6::CorePrivate INTERFACE_INCLUDE_DIRECTORIES)
+get_target_property(QT_GUI_PRIVATE_INCLUDES Qt6::GuiPrivate INTERFACE_INCLUDE_DIRECTORIES)
+
+set(target QIOSIntegrationPluginSwift)
+# Swift library
+set(SWIFT_SOURCES
+ "${CMAKE_CURRENT_SOURCE_DIR}/qiosapplication.swift"
+)
+add_library(${target} STATIC ${SWIFT_SOURCES})
+set_target_properties(${target} PROPERTIES
+ Swift_MODULE_NAME ${target})
+target_include_directories(${target} PUBLIC
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${QT_CORE_INCLUDES}"
+ "${QT_GUI_INCLUDES}"
+ "${QT_CORE_PRIVATE_INCLUDES}"
+ "${QT_GUI_PRIVATE_INCLUDES}"
+
+)
+target_compile_options(${target} PUBLIC
+ $<$<COMPILE_LANGUAGE:Swift>:-cxx-interoperability-mode=default>
+ $<$<COMPILE_LANGUAGE:Swift>:-Xcc -std=c++17>)
+
+# Swift to C++ bridging header
+set(SWIFT_BRIDGING_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qiosswiftintegration.h")
+list(TRANSFORM QT_CORE_INCLUDES PREPEND "-I")
+list(TRANSFORM QT_GUI_INCLUDES PREPEND "-I")
+list(TRANSFORM QT_CORE_PRIVATE_INCLUDES PREPEND "-I")
+list(TRANSFORM QT_GUI_PRIVATE_INCLUDES PREPEND "-I")
+add_custom_command(
+ COMMAND
+ ${CMAKE_Swift_COMPILER} -frontend -typecheck
+ ${SWIFT_SOURCES}
+ -I ${CMAKE_CURRENT_SOURCE_DIR}
+ ${QT_CORE_INCLUDES}
+ ${QT_GUI_INCLUDES}
+ ${QT_CORE_PRIVATE_INCLUDES}
+ ${QT_GUI_PRIVATE_INCLUDES}
+ -sdk ${CMAKE_OSX_SYSROOT}
+ -module-name ${target}
+ -cxx-interoperability-mode=default
+ -Xcc -std=c++17
+ -emit-clang-header-path "${SWIFT_BRIDGING_HEADER}"
+ -target ${CMAKE_Swift_COMPILER_TARGET}
+ OUTPUT
+ "${SWIFT_BRIDGING_HEADER}"
+ DEPENDS
+ ${SWIFT_SOURCES}
+ )
+
+set(header_target "${target}Header")
+add_custom_target(${header_target}
+ DEPENDS "${SWIFT_BRIDGING_HEADER}"
+)
+# Make sure the "'__bridge_transfer' casts have no effect when not using ARC"
+# warning doesn't break warnings-are-error builds.
+target_compile_options(${target} INTERFACE
+ -Wno-error=arc-bridge-casts-disallowed-in-nonarc)
+
+add_dependencies(${target} ${header_target})
diff --git a/src/plugins/platforms/ios/module.modulemap b/src/plugins/platforms/ios/module.modulemap
new file mode 100644
index 0000000000..af42b3e1f5
--- /dev/null
+++ b/src/plugins/platforms/ios/module.modulemap
@@ -0,0 +1,4 @@
+module QIOSIntegrationPlugin {
+ header "qiosapplicationdelegate.h"
+ header "qiosintegration.h"
+}
diff --git a/src/plugins/platforms/ios/qiosapplication.swift b/src/plugins/platforms/ios/qiosapplication.swift
new file mode 100644
index 0000000000..9eb172a896
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosapplication.swift
@@ -0,0 +1,198 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import SwiftUI
+import CompositorServices
+import QIOSIntegrationPlugin
+import RealityKit
+
+struct QIOSSwiftApplication: App {
+ @UIApplicationDelegateAdaptor private var appDelegate: QIOSApplicationDelegate
+
+ var body: some SwiftUI.Scene {
+ WindowGroup() {
+ ImmersiveSpaceControlView()
+ }
+
+ ImmersiveSpace(id: "QIOSImmersiveSpace") {
+ CompositorLayer(configuration: QIOSLayerConfiguration()) { layerRenderer in
+ QIOSIntegration.instance().renderCompositorLayer(layerRenderer)
+
+ // Handle any events in the scene.
+ layerRenderer.onSpatialEvent = { eventCollection in
+ QIOSIntegration.instance().handleSpatialEvents(jsonStringFromEventCollection(eventCollection))
+ }
+ }
+ }
+ // CompositorLayer immersive spaces are always full, and should not need
+ // to set the immersion style, but lacking this we get a warning in the
+ // console about not being able to "configure an immersive space with
+ // selected style 'AutomaticImmersionStyle' since it is not in the list
+ // of supported styles for this type of content: 'FullImmersionStyle'."
+ .immersionStyle(selection: .constant(.full), in: .full)
+ }
+}
+
+public struct QIOSLayerConfiguration: CompositorLayerConfiguration {
+ public func makeConfiguration(capabilities: LayerRenderer.Capabilities,
+ configuration: inout LayerRenderer.Configuration) {
+ // Use reflection to pull out underlying C handles
+ // FIXME: Use proper bridging APIs when available
+ let capabilitiesMirror = Mirror(reflecting: capabilities)
+ let configurationMirror = Mirror(reflecting: configuration)
+ QIOSIntegration.instance().configureCompositorLayer(
+ capabilitiesMirror.descendant("c_capabilities") as? cp_layer_renderer_capabilities_t,
+ configurationMirror.descendant("box", "value") as? cp_layer_renderer_configuration_t
+ )
+ }
+}
+
+public func runSwiftAppMain() {
+ QIOSSwiftApplication.main()
+}
+
+public class ImmersiveState: ObservableObject {
+ static let shared = ImmersiveState()
+ @Published var showImmersiveSpace: Bool = false
+}
+
+struct ImmersiveSpaceControlView: View {
+ @ObservedObject private var immersiveState = ImmersiveState.shared
+
+ @Environment(\.openImmersiveSpace) var openImmersiveSpace
+ @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
+
+ var body: some View {
+ VStack {}
+ .onChange(of: immersiveState.showImmersiveSpace) { _, newValue in
+ Task {
+ if newValue {
+ await openImmersiveSpace(id: "QIOSImmersiveSpace")
+ } else {
+ await dismissImmersiveSpace()
+ }
+ }
+ }
+ }
+}
+
+public class ImmersiveSpaceManager : NSObject {
+ @objc public static func openImmersiveSpace() {
+ ImmersiveState.shared.showImmersiveSpace = true
+ }
+
+ @objc public static func dismissImmersiveSpace() {
+ ImmersiveState.shared.showImmersiveSpace = false
+ }
+}
+
+extension SpatialEventCollection.Event.Kind: Encodable {
+ enum CodingKeys: String, CodingKey {
+ case touch
+ case directPinch
+ case indirectPinch
+ case pointer
+ }
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.singleValueContainer()
+ switch self {
+ case .touch:
+ try container.encode("touch")
+ case .directPinch:
+ try container.encode("directPinch")
+ case .indirectPinch:
+ try container.encode("indirectPinch")
+ case .pointer:
+ try container.encode("pointer")
+ @unknown default:
+ try container.encode("unknown")
+ }
+ }
+}
+extension SpatialEventCollection.Event.Phase: Encodable {
+ enum CodingKeys: String, CodingKey {
+ case active
+ case ending
+ case cancled
+ }
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.singleValueContainer()
+ switch self {
+ case .active:
+ try container.encode("active")
+ case .ended:
+ try container.encode("ended")
+ case .cancelled:
+ try container.encode("canceled")
+ @unknown default:
+ try container.encode("unknown")
+ }
+ }
+}
+extension SpatialEventCollection.Event.InputDevicePose: Encodable {
+ enum CodingKeys: String, CodingKey {
+ case altitude
+ case azimuth
+ case pose3D
+ }
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+ try container.encode(altitude.radians, forKey: .altitude)
+ try container.encode(azimuth.radians, forKey: .azimuth)
+ try container.encode(pose3D, forKey: .pose3D)
+ }
+}
+
+extension SpatialEventCollection.Event: Encodable {
+ enum CodingKeys: String, CodingKey {
+ case id
+ case timestamp
+ case kind
+ case location
+ case phase
+ case modifierKeys
+ case inputDevicePose
+ case location3D
+ case selectionRay
+ }
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+ try container.encode(id.hashValue, forKey: .id)
+ try container.encode(timestamp, forKey: .timestamp)
+ try container.encode(kind, forKey: .kind)
+ try container.encode(location, forKey: .location)
+ try container.encode(phase, forKey: .phase)
+ try container.encode(modifierKeys.rawValue, forKey: .modifierKeys)
+ try container.encode(inputDevicePose, forKey: .inputDevicePose)
+ try container.encode(location3D, forKey: .location3D)
+ try container.encode(selectionRay, forKey: .selectionRay)
+ }
+}
+
+extension SpatialEventCollection: Encodable {
+ enum CodingKeys: String, CodingKey {
+ case events
+ }
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+ try container.encode(Array(self), forKey: .events)
+ }
+}
+
+func jsonStringFromEventCollection(_ eventCollection: SpatialEventCollection) -> String {
+ let encoder = JSONEncoder()
+ encoder.dateEncodingStrategy = .iso8601
+
+ do {
+ let jsonData = try encoder.encode(eventCollection)
+ return String(data: jsonData, encoding: .utf8) ?? "{}"
+ } catch {
+ print("Failed to encode event collection: \(error)")
+ return "{}"
+ }
+}
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h
index 39bb9fdedb..7e12d64cbf 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.h
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h
@@ -1,6 +1,9 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QIOSAPPLICATIONDELEGATE_H
+#define QIOSAPPLICATIONDELEGATE_H
+
#import <UIKit/UIKit.h>
#import <QtGui/QtGui>
@@ -8,3 +11,5 @@
@interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate>
@end
+
+#endif // QIOSAPPLICATIONDELEGATE_H
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
index b40024ec19..5eee0556f5 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.h
+++ b/src/plugins/platforms/ios/qioseventdispatcher.h
@@ -16,6 +16,8 @@ public:
static QIOSEventDispatcher* create();
bool processPostedEvents() override;
+ static bool isQtApplication();
+
protected:
explicit QIOSEventDispatcher(QObject *parent = nullptr);
};
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index 24d9d88294..710a834bfd 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -5,6 +5,10 @@
#include "qiosapplicationdelegate.h"
#include "qiosglobal.h"
+#if defined(Q_OS_VISIONOS)
+#include "qiosswiftintegration.h"
+#endif
+
#include <QtCore/qprocessordetection.h>
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/private/qthread_p.h>
@@ -173,12 +177,16 @@ namespace
QAppleLogActivity UIApplicationMain;
QAppleLogActivity applicationDidFinishLaunching;
} logActivity;
+
+ static bool s_isQtApplication = false;
}
using namespace QT_PREPEND_NAMESPACE(QtPrivate);
extern "C" int qt_main_wrapper(int argc, char *argv[])
{
+ s_isQtApplication = true;
+
@autoreleasepool {
size_t defaultStackSize = 512 * kBytesPerKiloByte; // Same as secondary threads
@@ -202,8 +210,16 @@ extern "C" int qt_main_wrapper(int argc, char *argv[])
logActivity.UIApplicationMain = QT_APPLE_LOG_ACTIVITY(
lcEventDispatcher().isDebugEnabled(), "UIApplicationMain").enter();
+#if defined(Q_OS_VISIONOS)
+ Q_UNUSED(argc);
+ Q_UNUSED(argv);
+ qCDebug(lcEventDispatcher) << "Starting Swift app";
+ QIOSIntegrationPluginSwift::runSwiftAppMain();
+ Q_UNREACHABLE();
+#else
qCDebug(lcEventDispatcher) << "Running UIApplicationMain";
return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSApplicationDelegate class]));
+#endif
}
}
@@ -424,6 +440,11 @@ QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
QWindowSystemInterface::setSynchronousWindowSystemEvents(true);
}
+bool QIOSEventDispatcher::isQtApplication()
+{
+ return s_isQtApplication;
+}
+
/*!
Override of the CoreFoundation posted events runloop source callback
so that we can send window system (QPA) events in addition to sending
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
index 25ccf2961b..1722e09aaa 100644
--- a/src/plugins/platforms/ios/qiosglobal.mm
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -5,6 +5,8 @@
#include "qiosapplicationdelegate.h"
#include "qiosviewcontroller.h"
#include "qiosscreen.h"
+#include "quiwindow.h"
+#include "qioseventdispatcher.h"
#include <QtCore/private/qcore_mac_p.h>
@@ -17,17 +19,13 @@ Q_LOGGING_CATEGORY(lcQpaWindowScene, "qt.qpa.window.scene");
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 = ([qt_apple_sharedApplication().delegate isKindOfClass:[QIOSApplicationDelegate class]]);
- return isQt;
+ return QIOSEventDispatcher::isQtApplication();
}
bool isRunningOnVisionOS()
@@ -126,9 +124,15 @@ UIView *rootViewForScreen(QScreen *screen)
Q_UNUSED(iosScreen);
#endif
- UIWindow *uiWindow = windowScene.keyWindow;
- if (!uiWindow && windowScene.windows.count)
- uiWindow = windowScene.windows[0];
+ UIWindow *uiWindow = qt_objc_cast<QUIWindow*>(windowScene.keyWindow);
+ if (!uiWindow) {
+ for (UIWindow *win in windowScene.windows) {
+ if (qt_objc_cast<QUIWindow*>(win)) {
+ uiWindow = win;
+ break;
+ }
+ }
+ }
return uiWindow.rootViewController.view;
}
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index 2c7d33cc94..6c2014d048 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -16,11 +16,24 @@
#include "qiostextinputoverlay.h"
#endif
+#if defined(Q_OS_VISIONOS)
+#include <swift/bridging>
+#endif
+
QT_BEGIN_NAMESPACE
+using namespace QNativeInterface;
+
class QIOSServices;
-class QIOSIntegration : public QPlatformNativeInterface, public QPlatformIntegration
+class
+#if defined(Q_OS_VISIONOS)
+ SWIFT_IMMORTAL_REFERENCE
+#endif
+QIOSIntegration : public QPlatformNativeInterface, public QPlatformIntegration
+#if defined(Q_OS_VISIONOS)
+ , public QVisionOSApplication
+#endif
{
Q_OBJECT
public:
@@ -77,6 +90,18 @@ public:
QIOSApplicationState applicationState;
+#if defined(Q_OS_VISIONOS)
+ void openImmersiveSpace() override;
+ void dismissImmersiveSpace() override;
+
+ using CompositorLayer = QVisionOSApplication::ImmersiveSpaceCompositorLayer;
+ void setImmersiveSpaceCompositorLayer(CompositorLayer *layer) override;
+
+ void configureCompositorLayer(cp_layer_renderer_capabilities_t, cp_layer_renderer_configuration_t);
+ void renderCompositorLayer(cp_layer_renderer_t);
+ void handleSpatialEvents(const char *jsonString);
+#endif
+
private:
QPlatformFontDatabase *m_fontDatabase;
#if QT_CONFIG(clipboard)
@@ -90,6 +115,10 @@ private:
#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QIOSTextInputOverlay m_textInputOverlay;
#endif
+
+#if defined(Q_OS_VISIONOS)
+ CompositorLayer *m_immersiveSpaceCompositorLayer = nullptr;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 7cd21f83f6..76173ce830 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -17,6 +17,10 @@
#include "qiosservices.h"
#include "qiosoptionalplugininterface.h"
+#if defined(Q_OS_VISIONOS)
+#include "qiosswiftintegration.h"
+#endif
+
#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qrhibackingstore_p.h>
@@ -296,6 +300,52 @@ void QIOSIntegration::setApplicationBadge(qint64 number)
// ---------------------------------------------------------
+#if defined(Q_OS_VISIONOS)
+void QIOSIntegration::openImmersiveSpace()
+{
+ [ImmersiveSpaceManager openImmersiveSpace];
+}
+
+void QIOSIntegration::dismissImmersiveSpace()
+{
+ [ImmersiveSpaceManager dismissImmersiveSpace];
+}
+
+void QIOSIntegration::setImmersiveSpaceCompositorLayer(CompositorLayer *layer)
+{
+ m_immersiveSpaceCompositorLayer = layer;
+}
+
+void QIOSIntegration::configureCompositorLayer(cp_layer_renderer_capabilities_t capabilities,
+ cp_layer_renderer_configuration_t configuration)
+{
+ if (m_immersiveSpaceCompositorLayer)
+ m_immersiveSpaceCompositorLayer->configure(capabilities, configuration);
+}
+
+void QIOSIntegration::renderCompositorLayer(cp_layer_renderer_t renderer)
+{
+ if (m_immersiveSpaceCompositorLayer)
+ m_immersiveSpaceCompositorLayer->render(renderer);
+}
+
+void QIOSIntegration::handleSpatialEvents(const char *jsonString)
+{
+ if (m_immersiveSpaceCompositorLayer) {
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(QByteArray(jsonString), &error);
+ if (error.error != QJsonParseError::NoError) {
+ qWarning() << "Error parsing JSON: " << error.errorString();
+ return;
+ }
+ m_immersiveSpaceCompositorLayer->handleSpatialEvents(doc.object());
+ }
+}
+
+#endif
+
+// ---------------------------------------------------------
+
void *QIOSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
{
if (!window || !window->handle())
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index 7559979f33..8f3081e276 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -322,7 +322,10 @@ QDpi QIOSScreen::logicalBaseDpi() const
qreal QIOSScreen::devicePixelRatio() const
{
#if defined(Q_OS_VISIONOS)
- return 2.0; // Based on what iPad app reports
+ // Based on what iPad app reports, and what Apple
+ // documents to be the default scale factor on
+ // visionOS, and the minimum scale for assets.
+ return 2.0;
#else
return [m_uiScreen scale];
#endif
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index 88afee80c3..86bcc111d3 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -71,10 +71,9 @@ private:
UIView *m_view;
QRect m_normalGeometry;
- int m_windowLevel;
void raiseOrLower(bool raise);
- void updateWindowLevel();
+ int windowLevel() const;
bool blockedByModal();
friend class QIOSScreen;
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index f461a5f55b..7cd3d5f0b0 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -36,7 +36,6 @@ enum {
QIOSWindow::QIOSWindow(QWindow *window, WId nativeHandle)
: QPlatformWindow(window)
- , m_windowLevel(0)
{
if (nativeHandle) {
m_view = reinterpret_cast<UIView *>(nativeHandle);
@@ -127,11 +126,6 @@ void QIOSWindow::setVisible(bool visible)
if (!isQtApplication() || !window()->isTopLevel())
return;
- // Since iOS doesn't do window management the way a Qt application
- // expects, we need to raise and activate windows ourselves:
- if (visible)
- updateWindowLevel();
-
if (blockedByModal()) {
if (visible)
raise();
@@ -343,8 +337,8 @@ void QIOSWindow::raiseOrLower(bool raise)
UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]);
if (view.hidden || view == m_view || !view.qwindow)
continue;
- int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel;
- if (m_windowLevel > level || (raise && m_windowLevel == level)) {
+ int level = static_cast<QIOSWindow *>(view.qwindow->handle())->windowLevel();
+ if (windowLevel() > level || (raise && windowLevel() == level)) {
[m_view.superview insertSubview:m_view aboveSubview:view];
return;
}
@@ -359,30 +353,34 @@ void QIOSWindow::raiseOrLower(bool raise)
}
}
-void QIOSWindow::updateWindowLevel()
+int QIOSWindow::windowLevel() const
{
Qt::WindowType type = window()->type();
+ int level = 0;
+
if (type == Qt::ToolTip)
- m_windowLevel = 120;
+ level = 120;
else if (window()->flags() & Qt::WindowStaysOnTopHint)
- m_windowLevel = 100;
+ level = 100;
else if (window()->isModal())
- m_windowLevel = 40;
+ level = 40;
else if (type == Qt::Popup)
- m_windowLevel = 30;
+ level = 30;
else if (type == Qt::SplashScreen)
- m_windowLevel = 20;
+ level = 20;
else if (type == Qt::Tool)
- m_windowLevel = 10;
+ level = 10;
else
- m_windowLevel = 0;
+ level = 0;
- // A window should be in at least the same m_windowLevel as its parent:
+ // A window should be in at least the same window level as its parent
QWindow *transientParent = window()->transientParent();
QIOSWindow *transientParentWindow = transientParent ? static_cast<QIOSWindow *>(transientParent->handle()) : 0;
if (transientParentWindow)
- m_windowLevel = qMax(transientParentWindow->m_windowLevel, m_windowLevel);
+ level = qMax(transientParentWindow->windowLevel(), level);
+
+ return level;
}
void QIOSWindow::applicationStateChanged(Qt::ApplicationState)
@@ -396,6 +394,15 @@ void QIOSWindow::applicationStateChanged(Qt::ApplicationState)
qreal QIOSWindow::devicePixelRatio() const
{
+#if !defined(Q_OS_VISIONOS)
+ // If the view has not yet been added to a screen, it will not
+ // pick up its device pixel ratio, so we need to do so manually
+ // based on the screen we think the window will be added to.
+ if (!m_view.window.windowScene.screen)
+ return screen()->devicePixelRatio();
+#endif
+
+ // Otherwise we can rely on the content scale factor
return m_view.contentScaleFactor;
}
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm
index 39b2cb8a50..fa54f61967 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.mm
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm
@@ -10,6 +10,8 @@
#include "uistrings_p.h"
#include "qioswindow.h"
+#include <QtGui/private/qaccessiblebridgeutils_p.h>
+
QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
@implementation QMacAccessibilityElement
@@ -70,6 +72,17 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
return iface->text(QAccessible::Name).toNSString();
}
+
+- (NSString*)accessibilityIdentifier
+{
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
+ if (!iface) {
+ qWarning() << "invalid accessible interface for: " << self.axid;
+ return @"";
+ }
+ return QAccessibleBridgeUtils::accessibleId(iface).toNSString();
+}
+
- (NSString*)accessibilityHint
{
QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid);
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index d5808db305..cc4b92b92b 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -92,7 +92,16 @@ inline ulong getTimeStamp(UIEvent *event)
{
if (self = [self initWithFrame:window->geometry().toCGRect()]) {
self.platformWindow = window;
+
+ if (isQtApplication())
+ self.hidden = YES;
+
m_accessibleElements = [[NSMutableArray<UIAccessibilityElement *> alloc] init];
+
+#ifndef Q_OS_TVOS
+ self.multipleTouchEnabled = YES;
+#endif
+
m_scrollGestureRecognizer = [[UIPanGestureRecognizer alloc]
initWithTarget:self
action:@selector(handleScroll:)];
@@ -109,6 +118,7 @@ inline ulong getTimeStamp(UIEvent *event)
m_lastScrollCursorPos = CGPointZero;
[self addGestureRecognizer:m_scrollGestureRecognizer];
+ // Set up layer
if ([self.layer isKindOfClass:CAMetalLayer.class]) {
QWindow *window = self.platformWindow->window();
if (QColorSpace colorSpace = window->format().colorSpace(); colorSpace.isValid()) {
@@ -119,17 +129,8 @@ inline ulong getTimeStamp(UIEvent *event)
qCDebug(lcQpaWindow) << "Set" << self << "color space to" << metalLayer.colorspace;
}
}
- }
-
- return self;
-}
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- if ((self = [super initWithFrame:frame])) {
#if QT_CONFIG(opengl)
- if ([self.layer isKindOfClass:[CAEAGLLayer class]]) {
- // Set up EAGL layer
+ else if ([self.layer isKindOfClass:[CAEAGLLayer class]]) {
CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
eaglLayer.opaque = TRUE;
eaglLayer.drawableProperties = @{
@@ -139,37 +140,13 @@ inline ulong getTimeStamp(UIEvent *event)
}
#endif
- if (isQtApplication())
- self.hidden = YES;
-
-#ifndef Q_OS_TVOS
- self.multipleTouchEnabled = YES;
+#if defined(Q_OS_VISIONOS)
+ // Although the "Drawing sharp layer-based content in visionOS" docs
+ // claim that by default a CALayer rasterizes at a 2x scale this does
+ // not seem to be the case in practice. So we explicitly set the view's
+ // scale factor based on the screen, where we hard-code it to 2.0.
+ self.contentScaleFactor = self.platformWindow->screen()->devicePixelRatio();
#endif
-
- if (qEnvironmentVariableIntValue("QT_IOS_DEBUG_WINDOW_MANAGEMENT")) {
- static CGFloat hue = 0.0;
- CGFloat lastHue = hue;
- for (CGFloat diff = 0; diff < 0.1 || diff > 0.9; diff = fabs(hue - lastHue))
- hue = drand48();
-
- #define colorWithBrightness(br) \
- [UIColor colorWithHue:hue saturation:0.5 brightness:br alpha:1.0].CGColor
-
- self.layer.borderColor = colorWithBrightness(1.0);
- self.layer.borderWidth = 1.0;
- }
-
- if (qEnvironmentVariableIsSet("QT_IOS_DEBUG_WINDOW_SAFE_AREAS")) {
- UIView *safeAreaOverlay = [[UIView alloc] initWithFrame:CGRectZero];
- [safeAreaOverlay setBackgroundColor:[UIColor colorWithRed:0.3 green:0.7 blue:0.9 alpha:0.3]];
- [self addSubview:safeAreaOverlay];
-
- safeAreaOverlay.translatesAutoresizingMaskIntoConstraints = NO;
- [safeAreaOverlay.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;
- [safeAreaOverlay.leftAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leftAnchor].active = YES;
- [safeAreaOverlay.rightAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.rightAnchor].active = YES;
- [safeAreaOverlay.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor].active = YES;
- }
}
return self;
diff --git a/src/plugins/platforms/linuxfb/CMakeLists.txt b/src/plugins/platforms/linuxfb/CMakeLists.txt
index 9f75f53828..ba18cea50c 100644
--- a/src/plugins/platforms/linuxfb/CMakeLists.txt
+++ b/src/plugins/platforms/linuxfb/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QLinuxFbIntegrationPlugin
OUTPUT_NAME qlinuxfb
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES linuxfb
+ DEFAULT_IF "linuxfb" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qlinuxfbintegration.cpp qlinuxfbintegration.h
diff --git a/src/plugins/platforms/minimal/CMakeLists.txt b/src/plugins/platforms/minimal/CMakeLists.txt
index f3683deccf..18d8828134 100644
--- a/src/plugins/platforms/minimal/CMakeLists.txt
+++ b/src/plugins/platforms/minimal/CMakeLists.txt
@@ -10,7 +10,7 @@ qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype)
qt_internal_add_plugin(QMinimalIntegrationPlugin
OUTPUT_NAME qminimal
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimal
+ DEFAULT_IF "minimal" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qminimalbackingstore.cpp qminimalbackingstore.h
diff --git a/src/plugins/platforms/minimalegl/CMakeLists.txt b/src/plugins/platforms/minimalegl/CMakeLists.txt
index a6ec8be781..b93f325b8f 100644
--- a/src/plugins/platforms/minimalegl/CMakeLists.txt
+++ b/src/plugins/platforms/minimalegl/CMakeLists.txt
@@ -10,7 +10,7 @@ qt_find_package(EGL)
qt_internal_add_plugin(QMinimalEglIntegrationPlugin
OUTPUT_NAME qminimalegl
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES minimalegl
+ DEFAULT_IF "minimalegl" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qminimaleglintegration.cpp qminimaleglintegration.h
diff --git a/src/plugins/platforms/offscreen/CMakeLists.txt b/src/plugins/platforms/offscreen/CMakeLists.txt
index 09ad9a384d..907c2c9cc6 100644
--- a/src/plugins/platforms/offscreen/CMakeLists.txt
+++ b/src/plugins/platforms/offscreen/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QOffscreenIntegrationPlugin
OUTPUT_NAME qoffscreen
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES offscreen
+ DEFAULT_IF "offscreen" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qoffscreencommon.cpp qoffscreencommon.h
diff --git a/src/plugins/platforms/qnx/CMakeLists.txt b/src/plugins/platforms/qnx/CMakeLists.txt
index 9fb412d8a4..0f9deaa00b 100644
--- a/src/plugins/platforms/qnx/CMakeLists.txt
+++ b/src/plugins/platforms/qnx/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QQnxIntegrationPlugin
OUTPUT_NAME qqnx
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES qnx
+ DEFAULT_IF "qnx" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp main.h
qqnxabstractcover.h
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index cc10f6a00e..b308c956f2 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -49,6 +49,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qrhibackingstore_p.h>
#if !defined(QT_NO_OPENGL)
#include "qqnxglcontext.h"
@@ -328,8 +329,19 @@ QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const
{
- qCDebug(lcQpaQnx) << Q_FUNC_INFO;
- return new QQnxRasterBackingStore(window);
+ QSurface::SurfaceType surfaceType = window->surfaceType();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO << surfaceType;
+ switch (surfaceType) {
+ case QSurface::RasterSurface:
+ return new QQnxRasterBackingStore(window);
+#if !defined(QT_NO_OPENGL)
+ // Return a QRhiBackingStore for non-raster surface windows
+ case QSurface::OpenGLSurface:
+ return new QRhiBackingStore(window);
+#endif
+ default:
+ return nullptr;
+ }
}
#if !defined(QT_NO_OPENGL)
diff --git a/src/plugins/platforms/qnx/qqnxkeytranslator.h b/src/plugins/platforms/qnx/qqnxkeytranslator.h
index 824f7ad523..5e0dd56e2e 100644
--- a/src/plugins/platforms/qnx/qqnxkeytranslator.h
+++ b/src/plugins/platforms/qnx/qqnxkeytranslator.h
@@ -55,7 +55,7 @@ int qtKeyForPrivateUseQnxKey( int key )
case KEYCODE_KP_UP: return Qt::Key_Up;
case KEYCODE_KP_PG_UP: return Qt::Key_PageUp;
case KEYCODE_KP_LEFT: return Qt::Key_Left;
- case KEYCODE_KP_FIVE: return Qt::Key_5;
+ case KEYCODE_KP_FIVE: return Qt::Key_Clear;
case KEYCODE_KP_RIGHT: return Qt::Key_Right;
case KEYCODE_KP_END: return Qt::Key_End;
case KEYCODE_KP_DOWN: return Qt::Key_Down;
diff --git a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
index 719e5c45e6..406487f1e9 100644
--- a/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
+++ b/src/plugins/platforms/vkkhrdisplay/CMakeLists.txt
@@ -6,7 +6,7 @@ qt_find_package(WrapFreetype PROVIDED_TARGETS WrapFreetype::WrapFreetype)
qt_internal_add_plugin(QVkKhrDisplayIntegrationPlugin
OUTPUT_NAME qvkkhrdisplay
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vkkhrdisplay
+ DEFAULT_IF "vkkhrdisplay" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qvkkhrdisplayintegration.cpp qvkkhrdisplayintegration.h
diff --git a/src/plugins/platforms/vnc/CMakeLists.txt b/src/plugins/platforms/vnc/CMakeLists.txt
index 25cb399bd0..34370807ae 100644
--- a/src/plugins/platforms/vnc/CMakeLists.txt
+++ b/src/plugins/platforms/vnc/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QVncIntegrationPlugin
OUTPUT_NAME qvnc
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES vnc
+ DEFAULT_IF "vnc" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qvnc.cpp qvnc_p.h
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
index 90c7ec2118..caf5d3dff6 100644
--- a/src/plugins/platforms/wasm/CMakeLists.txt
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QWasmIntegrationPlugin
OUTPUT_NAME qwasm
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES wasm
+ DEFAULT_IF "wasm" IN_LIST QT_QPA_PLATFORMS
PLUGIN_TYPE platforms
SOURCES
main.cpp
@@ -44,6 +44,8 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
+ ATTRIBUTION_FILE_DIR_PATHS
+ ../../../3rdparty/wasm
)
# Resources:
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
index 4c3cb46ba3..2e430176be 100644
--- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
@@ -284,6 +284,10 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
element = document.call<emscripten::val>("createElement", std::string("div"));
}
+ QString id = QAccessibleBridgeUtils::accessibleId(iface);
+ if (iface->role() != QAccessible::PageTabList)
+ element.call<void>("setAttribute", std::string("id"), id.toStdString());
+
return element;
}();
diff --git a/src/plugins/platforms/wasm/qwasmdom.cpp b/src/plugins/platforms/wasm/qwasmdom.cpp
index 6b2b3d0933..96790ca71f 100644
--- a/src/plugins/platforms/wasm/qwasmdom.cpp
+++ b/src/plugins/platforms/wasm/qwasmdom.cpp
@@ -104,7 +104,10 @@ void DataTransfer::toMimeDataWithFile(std::function<void(QMimeData *)> callback)
if (--m_remainingItemCount > 0)
return;
- mimeData->setUrls(fileUrls);
+ QList<QUrl> allUrls;
+ allUrls.append(mimeData->urls());
+ allUrls.append(fileUrls);
+ mimeData->setUrls(allUrls);
m_callback(mimeData);
@@ -201,7 +204,11 @@ void DataTransfer::toMimeDataWithFile(std::function<void(QMimeData *)> callback)
mimeContext->mimeData->setHtml(data);
else if (itemMimeType.isEmpty() || itemMimeType == "text/plain")
mimeContext->mimeData->setText(data); // the type can be empty
- else {
+ else if (itemMimeType.isEmpty() || itemMimeType == "text/uri-list") {
+ QList<QUrl> urls;
+ urls.append(data);
+ mimeContext->mimeData->setUrls(urls);
+ } else {
// TODO improve encoding
if (data.startsWith("QB64")) {
data.remove(0, 4);
diff --git a/src/plugins/platforms/wasm/qwasmevent.cpp b/src/plugins/platforms/wasm/qwasmevent.cpp
index c1d6ce3a2a..e418263655 100644
--- a/src/plugins/platforms/wasm/qwasmevent.cpp
+++ b/src/plugins/platforms/wasm/qwasmevent.cpp
@@ -106,7 +106,7 @@ KeyEvent::KeyEvent(EventType type, emscripten::val event) : Event(type, event)
const auto code = event["code"].as<std::string>();
const auto webKey = event["key"].as<std::string>();
deadKey = isDeadKeyEvent(webKey.c_str());
-
+ autoRepeat = event["repeat"].as<bool>();
modifiers = KeyboardModifier::getForEvent(event);
key = webKeyToQtKey(code, webKey, deadKey, modifiers);
diff --git a/src/plugins/platforms/wasm/qwasmevent.h b/src/plugins/platforms/wasm/qwasmevent.h
index 6ada5393e3..bd0fb39f11 100644
--- a/src/plugins/platforms/wasm/qwasmevent.h
+++ b/src/plugins/platforms/wasm/qwasmevent.h
@@ -153,6 +153,7 @@ struct KeyEvent : public Event
QFlags<Qt::KeyboardModifier> modifiers;
bool deadKey;
QString text;
+ bool autoRepeat;
};
struct MouseEvent : public Event
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
index b8197c5113..99e9bb22f1 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -128,9 +128,8 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
});
emscripten::val keyFocusWindow;
- if (QWasmIntegration::get()->inputContext()) {
- QWasmInputContext *wasmContext =
- static_cast<QWasmInputContext *>(QWasmIntegration::get()->inputContext());
+ if (QWasmInputContext *wasmContext =
+ qobject_cast<QWasmInputContext *>(QWasmIntegration::get()->inputContext())) {
// if there is an touchscreen input context,
// use that window for key input
keyFocusWindow = wasmContext->m_inputElement;
@@ -502,7 +501,7 @@ bool QWasmWindow::processKey(const KeyEvent &event)
const auto result = QWindowSystemInterface::handleKeyEvent(
0, event.type == EventType::KeyDown ? QEvent::KeyPress : QEvent::KeyRelease, event.key,
- event.modifiers, event.text);
+ event.modifiers, event.text, event.autoRepeat);
return clipboardResult == ProcessKeyboardResult::NativeClipboardEventAndCopiedDataNeeded
? ProceedToNativeEvent
: result;
diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html
index 702ea1f59d..6e93955552 100644
--- a/src/plugins/platforms/wasm/wasm_shell.html
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -1,3 +1,8 @@
+<!--
+Copyright (C) 2024 The Qt Company Ltd.
+SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+-->
+
<!doctype html>
<html lang="en-us">
<head>
diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt
index 4b92317978..bbb8c46cf6 100644
--- a/src/plugins/platforms/windows/CMakeLists.txt
+++ b/src/plugins/platforms/windows/CMakeLists.txt
@@ -8,7 +8,7 @@
qt_internal_add_plugin(QWindowsIntegrationPlugin
OUTPUT_NAME qwindows
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES windows
+ DEFAULT_IF "windows" IN_LIST QT_QPA_PLATFORMS
SOURCES
main.cpp
qtwindowsglobal.h
@@ -28,7 +28,6 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin
qwindowskeymapper.cpp qwindowskeymapper.h
qwindowsmenu.cpp qwindowsmenu.h
qwindowsmimeregistry.cpp qwindowsmimeregistry.h
- qwindowsmousehandler.cpp qwindowsmousehandler.h
qwindowsnativeinterface.cpp qwindowsnativeinterface.h
qwindowsole.cpp qwindowsole.h
qwindowsopengltester.cpp qwindowsopengltester.h
@@ -132,6 +131,8 @@ qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_tablete
qwindowstabletsupport.cpp qwindowstabletsupport.h
INCLUDE_DIRECTORIES
${QtBase_SOURCE_DIR}/src/3rdparty/wintab
+ ATTRIBUTION_FILE_DIR_PATHS
+ ../../../3rdparty/wintab
)
qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_sessionmanager
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index de65a2171d..11a9290a2e 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -7,7 +7,6 @@
#include "qwindowswindow.h"
#include "qwindowskeymapper.h"
#include "qwindowsnativeinterface.h"
-#include "qwindowsmousehandler.h"
#include "qwindowspointerhandler.h"
#include "qtwindowsglobal.h"
#include "qwindowsmenu.h"
@@ -141,7 +140,6 @@ struct QWindowsContextPrivate {
HDC m_displayContext = nullptr;
int m_defaultDPI = 96;
QWindowsKeyMapper m_keyMapper;
- QWindowsMouseHandler m_mouseHandler;
QWindowsPointerHandler m_pointerHandler;
QWindowsMimeRegistry m_mimeConverter;
QWindowsScreenManager m_screenManager;
@@ -162,7 +160,7 @@ bool QWindowsContextPrivate::m_v2DpiAware = false;
QWindowsContextPrivate::QWindowsContextPrivate()
: m_oleInitializeResult(OleInitialize(nullptr))
{
- if (m_pointerHandler.touchDevice() || m_mouseHandler.touchDevice())
+ if (m_pointerHandler.touchDevice())
m_systemInfo |= QWindowsContext::SI_SupportsTouch;
m_displayContext = GetDC(nullptr);
m_defaultDPI = GetDeviceCaps(m_displayContext, LOGPIXELSY);
@@ -201,6 +199,8 @@ QWindowsContext::~QWindowsContext()
if (d->m_powerDummyWindow)
DestroyWindow(d->m_powerDummyWindow);
+ d->m_screenManager.destroyWindow();
+
unregisterWindowClasses();
if (d->m_oleInitializeResult == S_OK || d->m_oleInitializeResult == S_FALSE) {
#ifdef QT_USE_FACTORY_CACHE_REGISTRATION
@@ -224,8 +224,7 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
{
if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch)
return true;
- const bool usePointerHandler = (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) != 0;
- auto touchDevice = usePointerHandler ? d->m_pointerHandler.touchDevice() : d->m_mouseHandler.touchDevice();
+ auto touchDevice = d->m_pointerHandler.touchDevice();
if (touchDevice.isNull()) {
const bool mouseEmulation =
(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch) == 0;
@@ -234,7 +233,6 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
if (touchDevice.isNull())
return false;
d->m_pointerHandler.setTouchDevice(touchDevice);
- d->m_mouseHandler.setTouchDevice(touchDevice);
QWindowSystemInterface::registerInputDevice(touchDevice.data());
d->m_systemInfo |= QWindowsContext::SI_SupportsTouch;
@@ -274,15 +272,6 @@ bool QWindowsContext::disposeTablet()
#endif
}
-bool QWindowsContext::initPointer(unsigned integrationOptions)
-{
- if (integrationOptions & QWindowsIntegration::DontUseWMPointer)
- return false;
-
- d->m_systemInfo |= QWindowsContext::SI_SupportsPointer;
- return true;
-}
-
extern "C" LRESULT QT_WIN_CALLBACK qWindowsPowerWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message != WM_POWERBROADCAST || wParam != PBT_POWERSETTINGCHANGE)
@@ -728,16 +717,12 @@ QWindow *QWindowsContext::findWindow(HWND hwnd) const
QWindow *QWindowsContext::windowUnderMouse() const
{
- return (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) ?
- d->m_pointerHandler.windowUnderMouse() : d->m_mouseHandler.windowUnderMouse();
+ return d->m_pointerHandler.windowUnderMouse();
}
void QWindowsContext::clearWindowUnderMouse()
{
- if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
- d->m_pointerHandler.clearWindowUnderMouse();
- else
- d->m_mouseHandler.clearWindowUnderMouse();
+ d->m_pointerHandler.clearWindowUnderMouse();
}
/*!
@@ -1050,8 +1035,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
switch (et) {
case QtWindows::GestureEvent:
- if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
+ // TODO???
break;
case QtWindows::InputMethodOpenCandidateWindowEvent:
case QtWindows::InputMethodCloseCandidateWindowEvent:
@@ -1191,16 +1175,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::NonClientMouseEvent:
if (!platformWindow->frameStrutEventsEnabled())
break;
- if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
- return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
- else
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
+ return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
case QtWindows::NonClientPointerEvent:
if (!platformWindow->frameStrutEventsEnabled())
break;
- if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
- return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
- break;
+ return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
case QtWindows::EnterSizeMoveEvent:
platformWindow->setFlag(QWindowsWindow::ResizeMoveActive);
if (!IsZoomed(hwnd))
@@ -1214,8 +1193,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
platformWindow->updateRestoreGeometry();
return true;
case QtWindows::ScrollEvent:
- if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
+ // TODO???
break;
case QtWindows::MouseWheelEvent:
case QtWindows::MouseEvent:
@@ -1226,20 +1204,14 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
window = window->parent();
if (!window)
return false;
- if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
- return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
- else
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
+ return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
}
break;
case QtWindows::TouchEvent:
- if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
+ // TODO???
break;
case QtWindows::PointerEvent:
- if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
- return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
- break;
+ return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow().
case QtWindows::FocusOutEvent:
handleFocusEvent(et, platformWindow);
@@ -1443,7 +1415,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
// Mouse is left in pressed state after press on size grip (inside window),
// no further mouse events are received
// For cases 1,3, intercept WM_EXITSIZEMOVE to sync the buttons.
- const Qt::MouseButtons currentButtons = QWindowsMouseHandler::queryMouseButtons();
+ const Qt::MouseButtons currentButtons = QWindowsPointerHandler::queryMouseButtons();
const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons();
if (currentButtons == appButtons)
return;
@@ -1459,10 +1431,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
currentButtons, button, type, keyboardModifiers);
}
}
- if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
- d->m_pointerHandler.clearEvents();
- else
- d->m_mouseHandler.clearEvents();
+ d->m_pointerHandler.clearEvents();
}
bool QWindowsContext::asyncExpose() const
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 0539a22afc..4e9be1af96 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -53,8 +53,7 @@ public:
enum SystemInfoFlags
{
SI_RTL_Extensions = 0x1,
- SI_SupportsTouch = 0x2,
- SI_SupportsPointer = 0x4,
+ SI_SupportsTouch = 0x2
};
// Verbose flag set by environment variable QT_QPA_VERBOSE
@@ -67,7 +66,6 @@ public:
bool initTouch(unsigned integrationOptions); // For calls from QWindowsIntegration::QWindowsIntegration() only.
void registerTouchWindows();
bool initTablet();
- bool initPointer(unsigned integrationOptions);
bool disposeTablet();
bool initPowerNotificationHandler();
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index c6f55c3509..b872ef2ad6 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -11,7 +11,7 @@
#include "qwindowsintegration.h"
#include "qwindowsdropdataobject.h"
#include "qwindowswindow.h"
-#include "qwindowsmousehandler.h"
+#include "qwindowspointerhandler.h"
#include "qwindowscursor.h"
#include "qwindowskeymapper.h"
@@ -341,7 +341,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
// In some rare cases, when a mouse button is released but the mouse is static,
// grfKeyState will not be updated with these released buttons until the mouse
// is moved. So we use the async key state given by queryMouseButtons() instead.
- Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons();
+ Qt::MouseButtons buttons = QWindowsPointerHandler::queryMouseButtons();
SCODE result = S_OK;
if (fEscapePressed || QWindowsDrag::isCanceled()) {
@@ -366,7 +366,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
const QPoint localPos = m_windowUnderMouse->handle()->mapFromGlobal(globalPos);
QWindowSystemInterface::handleMouseEvent(m_windowUnderMouse.data(),
QPointF(localPos), QPointF(globalPos),
- QWindowsMouseHandler::queryMouseButtons(),
+ QWindowsPointerHandler::queryMouseButtons(),
Qt::LeftButton, QEvent::MouseButtonRelease);
}
m_currentButtons = Qt::NoButton;
@@ -460,7 +460,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState,
const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
lastModifiers = toQtKeyboardModifiers(grfKeyState);
- lastButtons = QWindowsMouseHandler::queryMouseButtons();
+ lastButtons = QWindowsPointerHandler::queryMouseButtons();
const QPlatformDragQtResponse response =
QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(),
@@ -530,7 +530,7 @@ QWindowsOleDropTarget::DragLeave()
const auto *keyMapper = QWindowsContext::instance()->keyMapper();
lastModifiers = keyMapper->queryKeyboardModifiers();
- lastButtons = QWindowsMouseHandler::queryMouseButtons();
+ lastButtons = QWindowsPointerHandler::queryMouseButtons();
QWindowSystemInterface::handleDrag(m_window, nullptr, QPoint(), Qt::IgnoreAction,
Qt::NoButton, Qt::NoModifier);
@@ -559,7 +559,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
lastModifiers = toQtKeyboardModifiers(grfKeyState);
- lastButtons = QWindowsMouseHandler::queryMouseButtons();
+ lastButtons = QWindowsPointerHandler::queryMouseButtons();
const QPlatformDropQtResponse response =
QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(),
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 0281025b5b..4b524c7a2c 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -5,7 +5,6 @@
#include "qwindowscontext.h"
#include "qwindowswindow.h"
#include "qwindowsintegration.h"
-#include "qwindowsmousehandler.h"
#include <QtCore/qdebug.h>
#include <QtCore/qobject.h>
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index aa6be266da..487e1d47b6 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -173,8 +173,6 @@ static inline unsigned parseOptions(const QStringList &paramList,
options |= QWindowsIntegration::AlwaysUseNativeMenus;
} else if (param == u"menus=none") {
options |= QWindowsIntegration::NoNativeMenus;
- } else if (param == u"nowmpointer") {
- options |= QWindowsIntegration::DontUseWMPointer;
} else if (param == u"reverse") {
options |= QWindowsIntegration::RtlEnabled;
} else if (param == u"darkmode=0") {
@@ -209,10 +207,7 @@ void QWindowsIntegrationPrivate::parseOptions(QWindowsIntegration *q, const QStr
if (tabletAbsoluteRange >= 0)
QWindowsContext::setTabletAbsoluteRange(tabletAbsoluteRange);
- if (m_context.initPointer(m_options))
- QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
- else
- m_context.initTablet();
+ QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication.
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index c271207741..932a69a6b7 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -42,10 +42,9 @@ public:
DontUseColorFonts = QWindowsFontDatabase::DontUseColorFonts,
AlwaysUseNativeMenus = 0x100,
NoNativeMenus = 0x200,
- DontUseWMPointer = 0x400,
- DetectAltGrModifier = 0x800,
- RtlEnabled = 0x1000,
- FontDatabaseGDI = 0x2000
+ DetectAltGrModifier = 0x400,
+ RtlEnabled = 0x0800,
+ FontDatabaseGDI = 0x1000
};
explicit QWindowsIntegration(const QStringList &paramList);
diff --git a/src/plugins/platforms/windows/qwindowsmimeregistry.cpp b/src/plugins/platforms/windows/qwindowsmimeregistry.cpp
index 8d147e8fa0..71faf4fe3b 100644
--- a/src/plugins/platforms/windows/qwindowsmimeregistry.cpp
+++ b/src/plugins/platforms/windows/qwindowsmimeregistry.cpp
@@ -923,16 +923,8 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *
const bool canGetDibV5 = canGetData(CF_DIBV5, pDataObj);
const bool hasOrigDibV5 = canGetDibV5 ? hasOriginalDIBV5(pDataObj) : false;
qCDebug(lcQpaMime) << "canGetDibV5:" << canGetDibV5 << "hasOrigDibV5:" << hasOrigDibV5;
- if (hasOrigDibV5) {
- qCDebug(lcQpaMime) << "Decoding DIBV5";
- QImage img;
- QByteArray data = getData(CF_DIBV5, pDataObj);
- QBuffer buffer(&data);
- if (readDib(buffer, img))
- return img;
- }
- //PNG, MS Office place this (undocumented)
- if (canGetData(CF_PNG, pDataObj)) {
+ // PNG, MS Office place this (undocumented)
+ if (!hasOrigDibV5 && canGetData(CF_PNG, pDataObj)) {
qCDebug(lcQpaMime) << "Decoding PNG";
QImage img;
QByteArray data = getData(CF_PNG, pDataObj);
@@ -940,11 +932,11 @@ QVariant QWindowsMimeImage::convertToMime(const QString &mimeType, IDataObject *
return img;
}
}
- //Fallback to DIB
- if (canGetData(CF_DIB, pDataObj)) {
+
+ if (canGetDibV5 || canGetData(CF_DIB, pDataObj)) {
qCDebug(lcQpaMime) << "Decoding DIB";
QImage img;
- QByteArray data = getData(CF_DIBV5, pDataObj);
+ QByteArray data = getData(canGetDibV5 ? CF_DIBV5 : CF_DIB, pDataObj);
QBuffer buffer(&data);
if (readDib(buffer, img))
return img;
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
deleted file mode 100644
index 9af9fba408..0000000000
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ /dev/null
@@ -1,653 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qwindowsmousehandler.h"
-#include "qwindowskeymapper.h"
-#include "qwindowscontext.h"
-#include "qwindowswindow.h"
-#include "qwindowsintegration.h"
-#include "qwindowsscreen.h"
-
-#include <qpa/qwindowsysteminterface.h>
-#include <QtGui/qguiapplication.h>
-#include <QtGui/qscreen.h>
-#include <QtGui/qpointingdevice.h>
-#include <QtGui/qwindow.h>
-#include <QtGui/qcursor.h>
-
-#include <QtCore/qdebug.h>
-
-#include <memory>
-
-#include <windowsx.h>
-
-QT_BEGIN_NAMESPACE
-
-static inline void compressMouseMove(MSG *msg)
-{
- // Compress mouse move events
- if (msg->message == WM_MOUSEMOVE) {
- MSG mouseMsg;
- while (PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEFIRST,
- WM_MOUSELAST, PM_NOREMOVE)) {
- if (mouseMsg.message == WM_MOUSEMOVE) {
-#define PEEKMESSAGE_IS_BROKEN 1
-#ifdef PEEKMESSAGE_IS_BROKEN
- // Since the Windows PeekMessage() function doesn't
- // correctly return the wParam for WM_MOUSEMOVE events
- // if there is a key release event in the queue
- // _before_ the mouse event, we have to also consider
- // key release events (kls 2003-05-13):
- MSG keyMsg;
- bool done = false;
- while (PeekMessage(&keyMsg, nullptr, WM_KEYFIRST, WM_KEYLAST,
- PM_NOREMOVE)) {
- if (keyMsg.time < mouseMsg.time) {
- if ((keyMsg.lParam & 0xC0000000) == 0x40000000) {
- PeekMessage(&keyMsg, nullptr, keyMsg.message,
- keyMsg.message, PM_REMOVE);
- } else {
- done = true;
- break;
- }
- } else {
- break; // no key event before the WM_MOUSEMOVE event
- }
- }
- if (done)
- break;
-#else
- // Actually the following 'if' should work instead of
- // the above key event checking, but apparently
- // PeekMessage() is broken :-(
- if (mouseMsg.wParam != msg.wParam)
- break; // leave the message in the queue because
- // the key state has changed
-#endif
- // Update the passed in MSG structure with the
- // most recent one.
- msg->lParam = mouseMsg.lParam;
- msg->wParam = mouseMsg.wParam;
- // Extract the x,y coordinates from the lParam as we do in the WndProc
- msg->pt.x = GET_X_LPARAM(mouseMsg.lParam);
- msg->pt.y = GET_Y_LPARAM(mouseMsg.lParam);
- clientToScreen(msg->hwnd, &(msg->pt));
- // Remove the mouse move message
- PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEMOVE,
- WM_MOUSEMOVE, PM_REMOVE);
- } else {
- break; // there was no more WM_MOUSEMOVE event
- }
- }
- }
-}
-
-/*!
- \class QWindowsMouseHandler
- \brief Windows mouse handler
-
- Dispatches mouse and touch events. Separate for code cleanliness.
-
- \internal
-*/
-
-QWindowsMouseHandler::QWindowsMouseHandler() = default;
-
-const QPointingDevice *QWindowsMouseHandler::primaryMouse()
-{
- static QPointer<const QPointingDevice> result;
- if (!result)
- result = QPointingDevice::primaryPointingDevice();
- return result;
-}
-
-void QWindowsMouseHandler::clearEvents()
-{
- m_lastEventType = QEvent::None;
- m_lastEventButton = Qt::NoButton;
-}
-
-Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
-{
- Qt::MouseButtons result;
- const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
- if (GetAsyncKeyState(VK_LBUTTON) < 0)
- result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
- if (GetAsyncKeyState(VK_RBUTTON) < 0)
- result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
- if (GetAsyncKeyState(VK_MBUTTON) < 0)
- result |= Qt::MiddleButton;
- if (GetAsyncKeyState(VK_XBUTTON1) < 0)
- result |= Qt::XButton1;
- if (GetAsyncKeyState(VK_XBUTTON2) < 0)
- result |= Qt::XButton2;
- return result;
-}
-
-Q_CONSTINIT static QPoint lastMouseMovePos;
-
-namespace {
-struct MouseEvent {
- QEvent::Type type;
- Qt::MouseButton button;
-};
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug d, const MouseEvent &e)
-{
- QDebugStateSaver saver(d);
- d.nospace();
- d << "MouseEvent(" << e.type << ", " << e.button << ')';
- return d;
-}
-#endif // QT_NO_DEBUG_STREAM
-} // namespace
-
-static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON...
-{
- return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
-}
-
-static inline MouseEvent eventFromMsg(const MSG &msg)
-{
- switch (msg.message) {
- case WM_MOUSEMOVE:
- return {QEvent::MouseMove, Qt::NoButton};
- case WM_LBUTTONDOWN:
- return {QEvent::MouseButtonPress, Qt::LeftButton};
- case WM_LBUTTONUP:
- return {QEvent::MouseButtonRelease, Qt::LeftButton};
- case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press
- return {QEvent::MouseButtonPress, Qt::LeftButton};
- case WM_MBUTTONDOWN:
- return {QEvent::MouseButtonPress, Qt::MiddleButton};
- case WM_MBUTTONUP:
- return {QEvent::MouseButtonRelease, Qt::MiddleButton};
- case WM_MBUTTONDBLCLK:
- return {QEvent::MouseButtonPress, Qt::MiddleButton};
- case WM_RBUTTONDOWN:
- return {QEvent::MouseButtonPress, Qt::RightButton};
- case WM_RBUTTONUP:
- return {QEvent::MouseButtonRelease, Qt::RightButton};
- case WM_RBUTTONDBLCLK:
- return {QEvent::MouseButtonPress, Qt::RightButton};
- case WM_XBUTTONDOWN:
- return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
- case WM_XBUTTONUP:
- return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
- case WM_XBUTTONDBLCLK:
- return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
- case WM_NCMOUSEMOVE:
- return {QEvent::NonClientAreaMouseMove, Qt::NoButton};
- case WM_NCLBUTTONDOWN:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
- case WM_NCLBUTTONUP:
- return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton};
- case WM_NCLBUTTONDBLCLK:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
- case WM_NCMBUTTONDOWN:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
- case WM_NCMBUTTONUP:
- return {QEvent::NonClientAreaMouseButtonRelease, Qt::MiddleButton};
- case WM_NCMBUTTONDBLCLK:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::MiddleButton};
- case WM_NCRBUTTONDOWN:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
- case WM_NCRBUTTONUP:
- return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
- case WM_NCRBUTTONDBLCLK:
- return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
- default: // WM_MOUSELEAVE
- break;
- }
- return {QEvent::None, Qt::NoButton};
-}
-
-bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
- QtWindows::WindowsEventType et,
- MSG msg, LRESULT *result)
-{
- enum : quint64 { signatureMask = 0xffffff00, miWpSignature = 0xff515700 };
-
- if (et == QtWindows::MouseWheelEvent)
- return translateMouseWheelEvent(window, hwnd, msg, result);
-
- QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) {
- RECT clientArea;
- GetClientRect(hwnd, &clientArea);
- winEventPosition.setX(clientArea.right - winEventPosition.x());
- }
-
- QPoint clientPosition;
- QPoint globalPosition;
- if (et & QtWindows::NonClientEventFlag) {
- globalPosition = winEventPosition;
- clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition);
- } else {
- globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition);
- auto targetHwnd = hwnd;
- if (auto *pw = window->handle())
- targetHwnd = HWND(pw->winId());
- clientPosition = targetHwnd == hwnd
- ? winEventPosition
- : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPosition);
- }
-
- // Windows sends a mouse move with no buttons pressed to signal "Enter"
- // when a window is shown over the cursor. Discard the event and only use
- // it for generating QEvent::Enter to be consistent with other platforms -
- // X11 and macOS.
- bool discardEvent = false;
- if (msg.message == WM_MOUSEMOVE) {
- const bool samePosition = globalPosition == lastMouseMovePos;
- lastMouseMovePos = globalPosition;
- if (msg.wParam == 0 && (m_windowUnderMouse.isNull() || samePosition))
- discardEvent = true;
- }
-
- Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
-
- const QPointingDevice *device = primaryMouse();
-
- // Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
- static const bool passSynthesizedMouseEvents =
- !(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch);
- // Check for events synthesized from touch. Lower 7 bits are touch/pen index, bit 8 indicates touch.
- // However, when tablet support is active, extraInfo is a packet serial number. This is not a problem
- // since we do not want to ignore mouse events coming from a tablet.
- // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320.aspx
- const auto extraInfo = quint64(GetMessageExtraInfo());
- if ((extraInfo & signatureMask) == miWpSignature) {
- if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen.
- source = Qt::MouseEventSynthesizedBySystem;
- if (!m_touchDevice.isNull())
- device = m_touchDevice.data();
- if (!passSynthesizedMouseEvents)
- return false;
- }
- }
-
- const auto *keyMapper = QWindowsContext::instance()->keyMapper();
- const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
- const MouseEvent mouseEvent = eventFromMsg(msg);
- Qt::MouseButtons buttons;
-
- if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick)
- buttons = queryMouseButtons();
- else
- buttons = keyStateToMouseButtons(msg.wParam);
-
- // When the left/right mouse buttons are pressed over the window title bar
- // WM_NCLBUTTONDOWN/WM_NCRBUTTONDOWN messages are received. But no UP
- // messages are received on release, only WM_NCMOUSEMOVE/WM_MOUSEMOVE.
- // We detect it and generate the missing release events here. (QTBUG-75678)
- // The last event vars are cleared on QWindowsContext::handleExitSizeMove()
- // to avoid generating duplicated release events.
- if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
- && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
- && (m_lastEventButton & buttons) == 0) {
- auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
- QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
- QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition, globalPosition, buttons, m_lastEventButton,
- releaseType, keyModifiers, source);
- }
- m_lastEventType = mouseEvent.type;
- m_lastEventButton = mouseEvent.button;
-
- if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
- QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition,
- globalPosition, buttons,
- mouseEvent.button, mouseEvent.type,
- keyModifiers, source);
- return false; // Allow further event processing (dragging of windows).
- }
-
- *result = 0;
- if (msg.message == WM_MOUSELEAVE) {
- qCDebug(lcQpaEvents) << mouseEvent << "for" << window << "previous window under mouse="
- << m_windowUnderMouse << "tracked window=" << m_trackedWindow;
-
- // When moving out of a window, WM_MOUSEMOVE within the moved-to window is received first,
- // so if m_trackedWindow is not the window here, it means the cursor has left the
- // application.
- if (window == m_trackedWindow) {
- QWindow *leaveTarget = m_windowUnderMouse ? m_windowUnderMouse : m_trackedWindow;
- qCDebug(lcQpaEvents) << "Generating leave event for " << leaveTarget;
- QWindowSystemInterface::handleLeaveEvent(leaveTarget);
- m_trackedWindow = nullptr;
- m_windowUnderMouse = nullptr;
- }
- return true;
- }
-
- auto *platformWindow = static_cast<QWindowsWindow *>(window->handle());
-
- // If the window was recently resized via mouse double-click on the frame or title bar,
- // we don't get WM_LBUTTONDOWN or WM_LBUTTONDBLCLK for the second click,
- // but we will get at least one WM_MOUSEMOVE with left button down and the WM_LBUTTONUP,
- // which will result undesired mouse press and release events.
- // To avoid those, we ignore any events with left button down if we didn't
- // get the original WM_LBUTTONDOWN/WM_LBUTTONDBLCLK.
- if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONDBLCLK) {
- m_leftButtonDown = true;
- } else {
- const bool actualLeftDown = buttons & Qt::LeftButton;
- if (!m_leftButtonDown && actualLeftDown) {
- // Autocapture the mouse for current window to and ignore further events until release.
- // Capture is necessary so we don't get WM_MOUSELEAVEs to confuse matters.
- // This autocapture is released normally when button is released.
- if (!platformWindow->hasMouseCapture()) {
- platformWindow->applyCursor();
- platformWindow->setMouseGrabEnabled(true);
- platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
- qCDebug(lcQpaEvents) << "Automatic mouse capture for missing buttondown event" << window;
- }
- m_previousCaptureWindow = window;
- return true;
- }
- if (m_leftButtonDown && !actualLeftDown)
- m_leftButtonDown = false;
- }
-
- // In this context, neither an invisible nor a transparent window (transparent regarding mouse
- // events, "click-through") can be considered as the window under mouse.
- QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ?
- QWindowsScreen::windowAt(globalPosition, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT) : window;
- while (currentWindowUnderMouse && currentWindowUnderMouse->flags() & Qt::WindowTransparentForInput)
- currentWindowUnderMouse = currentWindowUnderMouse->parent();
- // QTBUG-44332: When Qt is running at low integrity level and
- // a Qt Window is parented on a Window of a higher integrity process
- // using QWindow::fromWinId() (for example, Qt running in a browser plugin)
- // ChildWindowFromPointEx() may not find the Qt window (failing with ERROR_ACCESS_DENIED)
- if (!currentWindowUnderMouse) {
- const QRect clientRect(QPoint(0, 0), window->size());
- if (clientRect.contains(winEventPosition))
- currentWindowUnderMouse = window;
- }
-
- compressMouseMove(&msg);
- // Qt expects the platform plugin to capture the mouse on
- // any button press until release.
- if (!platformWindow->hasMouseCapture()
- && (mouseEvent.type == QEvent::MouseButtonPress || mouseEvent.type == QEvent::MouseButtonDblClick)) {
- platformWindow->setMouseGrabEnabled(true);
- platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
- qCDebug(lcQpaEvents) << "Automatic mouse capture " << window;
- // Implement "Click to focus" for native child windows (unless it is a native widget window).
- if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window)
- window->requestActivate();
- } else if (platformWindow->hasMouseCapture()
- && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
- && mouseEvent.type == QEvent::MouseButtonRelease
- && !buttons) {
- platformWindow->setMouseGrabEnabled(false);
- qCDebug(lcQpaEvents) << "Releasing automatic mouse capture " << window;
- }
-
- const bool hasCapture = platformWindow->hasMouseCapture();
- const bool currentNotCapturing = hasCapture && currentWindowUnderMouse != window;
- // Enter new window: track to generate leave event.
- // If there is an active capture, only track if the current window is capturing,
- // so we don't get extra leave when cursor leaves the application.
- if (window != m_trackedWindow && !currentNotCapturing) {
- TRACKMOUSEEVENT tme;
- tme.cbSize = sizeof(TRACKMOUSEEVENT);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = hwnd;
- tme.dwHoverTime = HOVER_DEFAULT; //
- if (!TrackMouseEvent(&tme))
- qWarning("TrackMouseEvent failed.");
- m_trackedWindow = window;
- }
-
- // No enter or leave events are sent as long as there is an autocapturing window.
- if (!hasCapture || !platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)) {
- // Leave is needed if:
- // 1) There is no capture and we move from a window to another window.
- // Note: Leaving the application entirely is handled in WM_MOUSELEAVE case.
- // 2) There is capture and we move out of the capturing window.
- // 3) There is a new capture and we were over another window.
- if ((m_windowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
- && (!hasCapture || window == m_windowUnderMouse))
- || (hasCapture && m_previousCaptureWindow != window && m_windowUnderMouse
- && m_windowUnderMouse != window)) {
- qCDebug(lcQpaEvents) << "Synthetic leave for " << m_windowUnderMouse;
- QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse);
- if (currentNotCapturing) {
- // Clear tracking if capturing and current window is not the capturing window
- // to avoid leave when mouse actually leaves the application.
- m_trackedWindow = nullptr;
- // We are not officially in any window, but we need to set some cursor to clear
- // whatever cursor the left window had, so apply the cursor of the capture window.
- platformWindow->applyCursor();
- }
- }
- // Enter is needed if:
- // 1) There is no capture and we move to a new window.
- // 2) There is capture and we move into the capturing window.
- // 3) The capture just ended and we are over non-capturing window.
- if ((currentWindowUnderMouse && m_windowUnderMouse != currentWindowUnderMouse
- && (!hasCapture || currentWindowUnderMouse == window))
- || (m_previousCaptureWindow && window != m_previousCaptureWindow && currentWindowUnderMouse
- && currentWindowUnderMouse != m_previousCaptureWindow)) {
- QPoint localPosition;
- qCDebug(lcQpaEvents) << "Entering " << currentWindowUnderMouse;
- if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderMouse)) {
- localPosition = wumPlatformWindow->mapFromGlobal(globalPosition);
- wumPlatformWindow->applyCursor();
- }
- QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse, localPosition, globalPosition);
- }
- // We need to track m_windowUnderMouse separately from m_trackedWindow, as
- // Windows mouse tracking will not trigger WM_MOUSELEAVE for leaving window when
- // mouse capture is set.
- m_windowUnderMouse = currentWindowUnderMouse;
- }
-
- if (!discardEvent && mouseEvent.type != QEvent::None) {
- QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition, globalPosition, buttons,
- mouseEvent.button, mouseEvent.type,
- keyModifiers, source);
- }
- m_previousCaptureWindow = hasCapture ? window : nullptr;
- // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
- // is sent for unhandled WM_XBUTTONDOWN.
- return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
- || QWindowSystemInterface::flushWindowSystemEvents();
-}
-
-static bool isValidWheelReceiver(QWindow *candidate)
-{
- if (candidate) {
- const QWindow *toplevel = QWindowsWindow::topLevelOf(candidate);
- if (toplevel->handle() && toplevel->handle()->isForeignWindow())
- return true;
- if (const QWindowsWindow *ww = QWindowsWindow::windowsWindowOf(toplevel))
- return !ww->testFlag(QWindowsWindow::BlockedByModal);
- }
-
- return false;
-}
-
-static void redirectWheelEvent(QWindow *window, unsigned long timestamp, const QPoint &globalPos, int delta,
- Qt::Orientation orientation, Qt::KeyboardModifiers mods)
-{
- // Redirect wheel event to one of the following, in order of preference:
- // 1) The window under mouse
- // 2) The window receiving the event
- // If a window is blocked by modality, it can't get the event.
-
- QWindow *receiver = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE);
- while (receiver && receiver->flags().testFlag(Qt::WindowTransparentForInput))
- receiver = receiver->parent();
- bool handleEvent = true;
- if (!isValidWheelReceiver(receiver)) {
- receiver = window;
- if (!isValidWheelReceiver(receiver))
- handleEvent = false;
- }
-
- if (handleEvent) {
- const QPoint point = (orientation == Qt::Vertical) ? QPoint(0, delta) : QPoint(delta, 0);
- QWindowSystemInterface::handleWheelEvent(receiver,
- timestamp,
- QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
- globalPos, QPoint(), point, mods);
- }
-}
-
-bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
- MSG msg, LRESULT *)
-{
- const Qt::KeyboardModifiers mods = keyStateToModifiers(int(msg.wParam));
-
- int delta;
- if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL)
- delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
- else
- delta = int(msg.wParam);
-
- Qt::Orientation orientation = (msg.message == WM_MOUSEHWHEEL
- || (mods & Qt::AltModifier)) ?
- Qt::Horizontal : Qt::Vertical;
-
- // according to the MSDN documentation on WM_MOUSEHWHEEL:
- // a positive value indicates that the wheel was rotated to the right;
- // a negative value indicates that the wheel was rotated to the left.
- // Qt defines this value as the exact opposite, so we have to flip the value!
- if (msg.message == WM_MOUSEHWHEEL)
- delta = -delta;
-
- const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- redirectWheelEvent(window, msg.time, globalPos, delta, orientation, mods);
-
- return true;
-}
-
-bool QWindowsMouseHandler::translateScrollEvent(QWindow *window, HWND,
- MSG msg, LRESULT *)
-{
- // This is a workaround against some touchpads that send WM_HSCROLL instead of WM_MOUSEHWHEEL.
- // We could also handle vertical scroll here but there's no reason to, there's no bug for vertical
- // (broken vertical scroll would have been noticed long time ago), so lets keep the change small
- // and minimize the chance for regressions.
-
- int delta = 0;
- switch (LOWORD(msg.wParam)) {
- case SB_LINELEFT:
- delta = 120;
- break;
- case SB_LINERIGHT:
- delta = -120;
- break;
- case SB_PAGELEFT:
- delta = 240;
- break;
- case SB_PAGERIGHT:
- delta = -240;
- break;
- default:
- return false;
- }
-
- redirectWheelEvent(window, msg.time, QCursor::pos(), delta, Qt::Horizontal, Qt::NoModifier);
-
- return true;
-}
-
-// from bool QApplicationPrivate::translateTouchEvent()
-bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
- QtWindows::WindowsEventType,
- MSG msg, LRESULT *)
-{
- using QTouchPoint = QWindowSystemInterface::TouchPoint;
- using QTouchPointList = QList<QWindowSystemInterface::TouchPoint>;
-
- if (!QWindowsContext::instance()->initTouch()) {
- qWarning("Unable to initialize touch handling.");
- return true;
- }
-
- const QScreen *screen = window->screen();
- if (!screen)
- screen = QGuiApplication::primaryScreen();
- if (!screen)
- return true;
- const QRect screenGeometry = screen->geometry();
-
- const int winTouchPointCount = int(msg.wParam);
- const auto winTouchInputs = std::make_unique<TOUCHINPUT[]>(winTouchPointCount);
-
- QTouchPointList touchPoints;
- touchPoints.reserve(winTouchPointCount);
- QEventPoint::States allStates;
-
- GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(msg.lParam),
- UINT(msg.wParam), winTouchInputs.get(), sizeof(TOUCHINPUT));
- for (int i = 0; i < winTouchPointCount; ++i) {
- const TOUCHINPUT &winTouchInput = winTouchInputs[i];
- int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1);
- if (id == -1) {
- id = m_touchInputIDToTouchPointID.size();
- m_touchInputIDToTouchPointID.insert(winTouchInput.dwID, id);
- }
- QTouchPoint touchPoint;
- touchPoint.pressure = 1.0;
- touchPoint.id = id;
- if (m_lastTouchPositions.contains(id))
- touchPoint.normalPosition = m_lastTouchPositions.value(id);
-
- const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) / qreal(100.);
- if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
- touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) / qreal(100.));
- touchPoint.area.moveCenter(screenPos);
- QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(),
- screenPos.y() / screenGeometry.height());
- const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
- touchPoint.normalPosition = normalPosition;
-
- if (winTouchInput.dwFlags & TOUCHEVENTF_DOWN) {
- touchPoint.state = QEventPoint::State::Pressed;
- m_lastTouchPositions.insert(id, touchPoint.normalPosition);
- } else if (winTouchInput.dwFlags & TOUCHEVENTF_UP) {
- touchPoint.state = QEventPoint::State::Released;
- m_lastTouchPositions.remove(id);
- } else {
- touchPoint.state = (stationaryTouchPoint
- ? QEventPoint::State::Stationary
- : QEventPoint::State::Updated);
- m_lastTouchPositions.insert(id, touchPoint.normalPosition);
- }
-
- allStates |= touchPoint.state;
-
- touchPoints.append(touchPoint);
- }
-
- CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(msg.lParam));
-
- // all touch points released, forget the ids we've seen, they may not be reused
- if (allStates == QEventPoint::State::Released)
- m_touchInputIDToTouchPointID.clear();
-
- const auto *keyMapper = QWindowsContext::instance()->keyMapper();
- QWindowSystemInterface::handleTouchEvent(window,
- msg.time,
- m_touchDevice.data(),
- touchPoints,
- keyMapper->queryKeyboardModifiers());
- return true;
-}
-
-bool QWindowsMouseHandler::translateGestureEvent(QWindow *window, HWND hwnd,
- QtWindows::WindowsEventType,
- MSG msg, LRESULT *)
-{
- Q_UNUSED(window);
- Q_UNUSED(hwnd);
- Q_UNUSED(msg);
- return false;
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h
deleted file mode 100644
index 7fde349f58..0000000000
--- a/src/plugins/platforms/windows/qwindowsmousehandler.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QWINDOWSMOUSEHANDLER_H
-#define QWINDOWSMOUSEHANDLER_H
-
-#include "qtwindowsglobal.h"
-#include <QtCore/qt_windows.h>
-
-#include <QtCore/qpointer.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qsharedpointer.h>
-#include <QtGui/qevent.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWindow;
-class QPointingDevice;
-
-class QWindowsMouseHandler
-{
- Q_DISABLE_COPY_MOVE(QWindowsMouseHandler)
-public:
- using QPointingDevicePtr = QSharedPointer<QPointingDevice>;
-
- QWindowsMouseHandler();
-
- const QPointingDevicePtr &touchDevice() const { return m_touchDevice; }
- void setTouchDevice(const QPointingDevicePtr &d) { m_touchDevice = d; }
-
- bool translateMouseEvent(QWindow *widget, HWND hwnd,
- QtWindows::WindowsEventType t, MSG msg,
- LRESULT *result);
- bool translateTouchEvent(QWindow *widget, HWND hwnd,
- QtWindows::WindowsEventType t, MSG msg,
- LRESULT *result);
- bool translateGestureEvent(QWindow *window, HWND hwnd,
- QtWindows::WindowsEventType,
- MSG msg, LRESULT *);
- bool translateScrollEvent(QWindow *window, HWND hwnd,
- MSG msg, LRESULT *result);
-
- static inline Qt::MouseButtons keyStateToMouseButtons(WPARAM);
- static inline Qt::KeyboardModifiers keyStateToModifiers(int);
- static inline int mouseButtonsToKeyState(Qt::MouseButtons);
-
- static Qt::MouseButtons queryMouseButtons();
- QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); }
- void clearWindowUnderMouse() { m_windowUnderMouse = nullptr; }
- void clearEvents();
-
- static const QPointingDevice *primaryMouse();
-
-private:
- inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd,
- MSG msg, LRESULT *result);
-
- QPointer<QWindow> m_windowUnderMouse;
- QPointer<QWindow> m_trackedWindow;
- QHash<DWORD, int> m_touchInputIDToTouchPointID;
- QHash<int, QPointF> m_lastTouchPositions;
- QPointingDevicePtr m_touchDevice;
- bool m_leftButtonDown = false;
- QWindow *m_previousCaptureWindow = nullptr;
- QEvent::Type m_lastEventType = QEvent::None;
- Qt::MouseButton m_lastEventButton = Qt::NoButton;
-};
-
-Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(WPARAM wParam)
-{
- Qt::MouseButtons mb(Qt::NoButton);
- if (wParam & MK_LBUTTON)
- mb |= Qt::LeftButton;
- if (wParam & MK_MBUTTON)
- mb |= Qt::MiddleButton;
- if (wParam & MK_RBUTTON)
- mb |= Qt::RightButton;
- if (wParam & MK_XBUTTON1)
- mb |= Qt::XButton1;
- if (wParam & MK_XBUTTON2)
- mb |= Qt::XButton2;
- return mb;
-}
-
-Qt::KeyboardModifiers QWindowsMouseHandler::keyStateToModifiers(int wParam)
-{
- Qt::KeyboardModifiers mods(Qt::NoModifier);
- if (wParam & MK_CONTROL)
- mods |= Qt::ControlModifier;
- if (wParam & MK_SHIFT)
- mods |= Qt::ShiftModifier;
- if (GetKeyState(VK_MENU) < 0)
- mods |= Qt::AltModifier;
- return mods;
-}
-
-int QWindowsMouseHandler::mouseButtonsToKeyState(Qt::MouseButtons mb)
-{
- int result = 0;
- if (mb & Qt::LeftButton)
- result |= MK_LBUTTON;
- if (mb & Qt::MiddleButton)
- result |= MK_MBUTTON;
- if (mb & Qt::RightButton)
- result |= MK_RBUTTON;
- if (mb & Qt::XButton1)
- result |= MK_XBUTTON1;
- if (mb & Qt::XButton2)
- result |= MK_XBUTTON2;
- return result;
-}
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSMOUSEHANDLER_H
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp
index 6a790bcc1b..38d1cdd738 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.cpp
+++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp
@@ -65,7 +65,9 @@ private:
QDirect3D9Handle::QDirect3D9Handle()
{
+#ifndef QT_NO_OPENGL
m_direct3D9 = Direct3DCreate9(D3D_SDK_VERSION);
+#endif
}
QDirect3D9Handle::~QDirect3D9Handle()
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
index 71c7217671..7995716444 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -4,7 +4,6 @@
#include <QtCore/qt_windows.h>
#include "qwindowspointerhandler.h"
-#include "qwindowsmousehandler.h"
#if QT_CONFIG(tabletevent)
# include "qwindowstabletsupport.h"
#endif
@@ -39,6 +38,14 @@ enum {
qint64 QWindowsPointerHandler::m_nextInputDeviceId = 1;
+const QPointingDevice *primaryMouse()
+{
+ static QPointer<const QPointingDevice> result;
+ if (!result)
+ result = QPointingDevice::primaryPointingDevice();
+ return result;
+}
+
QWindowsPointerHandler::~QWindowsPointerHandler()
{
}
@@ -215,7 +222,7 @@ static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState)
return result;
}
-static Qt::MouseButtons queryMouseButtons()
+Qt::MouseButtons QWindowsPointerHandler::queryMouseButtons()
{
Qt::MouseButtons result = Qt::NoButton;
const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
@@ -785,7 +792,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
}
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
- const QPointingDevice *device = QWindowsMouseHandler::primaryMouse();
+ const QPointingDevice *device = primaryMouse();
// Following the logic of the old mouse handler, only events synthesized
// for touch screen are marked as such. On some systems, using the bit 7 of
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h
index b64a8c146a..1827dd9df0 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.h
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.h
@@ -38,12 +38,15 @@ public:
void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; }
void clearEvents();
+ static Qt::MouseButtons queryMouseButtons();
+
private:
bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count);
bool translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo);
bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers);
void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons);
void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos);
+
#if QT_CONFIG(tabletevent)
QPointingDevicePtr findTabletDevice(QPointingDevice::PointerType pointerType) const;
#endif
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index a50f9fd4b0..1f22fb4f60 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -698,11 +698,15 @@ void QWindowsScreenManager::initialize()
handleScreenChanges();
}
-QWindowsScreenManager::~QWindowsScreenManager()
+void QWindowsScreenManager::destroyWindow()
{
+ qCDebug(lcQpaScreen) << "Destroying display change observer" << m_displayChangeObserver;
DestroyWindow(m_displayChangeObserver);
+ m_displayChangeObserver = nullptr;
}
+QWindowsScreenManager::~QWindowsScreenManager() = default;
+
bool QWindowsScreenManager::isSingleScreen()
{
return QWindowsContext::instance()->screenManager().screens().size() < 2;
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index 0467ab2a0c..ea6a29efe3 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -105,6 +105,7 @@ public:
QWindowsScreenManager();
void initialize();
+ void destroyWindow();
~QWindowsScreenManager();
void clearScreens();
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index 96ae6197b4..a89fb1e5bd 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -33,7 +33,6 @@ public:
Qt::ColorScheme colorScheme() const override;
void requestColorScheme(Qt::ColorScheme scheme) override;
- Qt::ColorScheme requestedColorScheme() const { return s_colorSchemeOverride; }
static void handleSettingsChanged();
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index ee0b88ba54..4b7ce0a979 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -855,12 +855,6 @@ static inline bool shouldApplyDarkFrame(const QWindow *w)
if (!QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames))
return false;
- // the application explicitly overrides the color scheme
- if (const auto requestedColorScheme = QWindowsTheme::instance()->requestedColorScheme();
- requestedColorScheme != Qt::ColorScheme::Unknown) {
- return requestedColorScheme == Qt::ColorScheme::Dark;
- }
-
// if the application supports a dark border, and the palette is dark (window background color
// is darker than the text), then turn dark-border support on, otherwise use a light border.
auto *dWindow = QWindowPrivate::get(const_cast<QWindow*>(w));
@@ -2488,6 +2482,11 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
GetWindowPlacement(m_data.hwnd, &windowPlacement);
const RECT geometry = RECTfromQRect(m_data.restoreGeometry);
windowPlacement.rcNormalPosition = geometry;
+ // Even if the window is hidden, windowPlacement's showCmd is not SW_HIDE, so change it
+ // manually to avoid unhiding a hidden window with the subsequent call to
+ // SetWindowPlacement().
+ if (!isVisible())
+ windowPlacement.showCmd = SW_HIDE;
SetWindowPlacement(m_data.hwnd, &windowPlacement);
}
// QTBUG-17548: We send expose events when receiving WM_Paint, but for
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 024711e7f3..b3cddc11d8 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -347,6 +347,8 @@ public:
int savedDpi() const { return m_savedDpi; }
qreal dpiRelativeScale(const UINT dpi) const;
+ bool isFrameless() const { return m_data.flags.testFlag(Qt::FramelessWindowHint); }
+
private:
inline void show_sys() const;
inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
index 1abb412ccd..5892493281 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
@@ -127,6 +127,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
return;
switch (event->type()) {
+ case QAccessible::Announcement:
+ QWindowsUiaMainProvider::raiseNotification(static_cast<QAccessibleAnnouncementEvent *>(event));
+ break;
case QAccessible::Focus:
QWindowsUiaMainProvider::notifyFocusChange(event);
break;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index 95ddbcced6..07cd522746 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -23,6 +23,7 @@
#include "qwindowsuiaprovidercache.h"
#include <QtCore/qloggingcategory.h>
+#include <QtGui/private/qaccessiblebridgeutils_p.h>
#include <QtGui/qaccessible.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qwindow.h>
@@ -204,6 +205,24 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
}
}
+void QWindowsUiaMainProvider::raiseNotification(QAccessibleAnnouncementEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
+ BSTR message = bStrFromQString(event->message());
+ QAccessible::AnnouncementPriority prio = event->priority();
+ NotificationProcessing processing = (prio == QAccessible::AnnouncementPriority::Assertive)
+ ? NotificationProcessing_ImportantAll
+ : NotificationProcessing_All;
+ BSTR activityId = bStrFromQString(QString::fromLatin1(""));
+ UiaRaiseNotificationEvent(provider, NotificationKind_Other, processing, message, activityId);
+
+ ::SysFreeString(message);
+ ::SysFreeString(activityId);
+ }
+ }
+}
+
HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
{
HRESULT result = QComObject::QueryInterface(iid, iface);
@@ -370,6 +389,93 @@ void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface*
pRetVal->parray = elements;
}
+void QWindowsUiaMainProvider::setAriaProperties(QAccessibleInterface *accessible, VARIANT *pRetVal)
+{
+ Q_ASSERT(accessible);
+
+ QAccessibleAttributesInterface *attributesIface = accessible->attributesInterface();
+ if (!attributesIface)
+ return;
+
+ QString ariaString;
+ const QList<QAccessible::Attribute> attrKeys = attributesIface->attributeKeys();
+ for (qsizetype i = 0; i < attrKeys.size(); ++i) {
+ if (i != 0)
+ ariaString += QStringLiteral(";");
+ const QAccessible::Attribute key = attrKeys.at(i);
+ const QVariant value = attributesIface->attributeValue(key);
+ // see "Core Accessibility API Mappings" spec: https://www.w3.org/TR/core-aam-1.2/
+ switch (key) {
+ case QAccessible::Attribute::Custom:
+ {
+ // forward custom attributes as-is
+ Q_ASSERT((value.canConvert<QHash<QString, QString>>()));
+ const QHash<QString, QString> attrMap = value.value<QHash<QString, QString>>();
+ for (auto [name, val] : attrMap.asKeyValueRange()) {
+ if (name != *attrMap.keyBegin())
+ ariaString += QStringLiteral(";");
+ ariaString += name + QStringLiteral("=") + val;
+ }
+ break;
+ }
+ case QAccessible::Attribute::Level:
+ Q_ASSERT(value.canConvert<int>());
+ ariaString += QStringLiteral("level=") + QString::number(value.toInt());
+ break;
+ default:
+ break;
+ }
+ }
+
+ setVariantString(ariaString, pRetVal);
+}
+
+void QWindowsUiaMainProvider::setStyle(QAccessibleInterface *accessible, VARIANT *pRetVal)
+{
+ Q_ASSERT(accessible);
+
+ QAccessibleAttributesInterface *attributesIface = accessible->attributesInterface();
+ if (!attributesIface)
+ return;
+
+ // currently, only heading styles are implemented here
+ if (accessible->role() != QAccessible::Role::Heading)
+ return;
+
+ const QVariant levelVariant = attributesIface->attributeValue(QAccessible::Attribute::Level);
+ if (!levelVariant.isValid())
+ return;
+
+ Q_ASSERT(levelVariant.canConvert<int>());
+ // UIA only has styles for heading levels 1-9
+ const int level = levelVariant.toInt();
+ if (level < 1 || level > 9)
+ return;
+
+ const int styleId = styleIdForHeadingLevel(level);
+ setVariantI4(styleId, pRetVal);
+}
+
+int QWindowsUiaMainProvider::styleIdForHeadingLevel(int headingLevel)
+{
+ // only heading levels 1-9 have a corresponding UIA style ID
+ Q_ASSERT(headingLevel > 0 && headingLevel <= 9);
+
+ static constexpr int styles[] = {
+ StyleId_Heading1,
+ StyleId_Heading2,
+ StyleId_Heading3,
+ StyleId_Heading4,
+ StyleId_Heading5,
+ StyleId_Heading6,
+ StyleId_Heading7,
+ StyleId_Heading8,
+ StyleId_Heading9,
+ };
+
+ return styles[headingLevel - 1];
+}
+
HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal)
{
qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idProp;
@@ -393,9 +499,12 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
// Accelerator key.
setVariantString(accessible->text(QAccessible::Accelerator), pRetVal);
break;
+ case UIA_AriaPropertiesPropertyId:
+ setAriaProperties(accessible, pRetVal);
+ break;
case UIA_AutomationIdPropertyId:
// Automation ID, which can be used by tools to select a specific control in the UI.
- setVariantString(automationIdForAccessible(accessible), pRetVal);
+ setVariantString(QAccessibleBridgeUtils::accessibleId(accessible), pRetVal);
break;
case UIA_ClassNamePropertyId:
// Class name.
@@ -493,31 +602,15 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
setVariantString(name, pRetVal);
break;
}
+ case UIA_StyleIdAttributeId:
+ setStyle(accessible, pRetVal);
+ break;
default:
break;
}
return S_OK;
}
-// Generates an ID based on the name of the controls and their parents.
-QString QWindowsUiaMainProvider::automationIdForAccessible(const QAccessibleInterface *accessible)
-{
- QString result;
- if (accessible) {
- QObject *obj = accessible->object();
- while (obj) {
- QString name = obj->objectName();
- if (name.isEmpty())
- return result;
- if (!result.isEmpty())
- result.prepend(u'.');
- result.prepend(name);
- obj = obj->parent();
- }
- }
- return result;
-}
-
HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderSimple **pRetVal)
{
qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
index 99db0ed318..8ea343e425 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
@@ -34,6 +34,7 @@ public:
static void notifyNameChange(QAccessibleEvent *event);
static void notifySelectionChange(QAccessibleEvent *event);
static void notifyTextChange(QAccessibleEvent *event);
+ static void raiseNotification(QAccessibleAnnouncementEvent *event);
// IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
@@ -58,8 +59,11 @@ public:
HRESULT STDMETHODCALLTYPE GetFocus(IRawElementProviderFragment **pRetVal) override;
private:
- QString automationIdForAccessible(const QAccessibleInterface *accessible);
static void fillVariantArrayForRelation(QAccessibleInterface *accessible, QAccessible::Relation relation, VARIANT *pRetVal);
+ static void setAriaProperties(QAccessibleInterface *accessible, VARIANT *pRetVal);
+ static void setStyle(QAccessibleInterface *accessible, VARIANT *pRetVal);
+ /** Returns the UIA style ID for a heading level from 1 to 9. */
+ static int styleIdForHeadingLevel(int headingLevel);
static QMutex m_mutex;
};
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
index 1593a07202..6954a881d0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
@@ -69,6 +69,14 @@ HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *pProvider, EVE
return func.invoke(pProvider, id);
}
+HRESULT WINAPI UiaRaiseNotificationEvent(
+ IRawElementProviderSimple *pProvider, NotificationKind notificationKind,
+ NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaRaiseNotificationEvent));
+ return func.invoke(pProvider, notificationKind, notificationProcessing, displayString, activityId);
+}
+
#endif // defined(__MINGW32__) || defined(__MINGW64__)
#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
index a192b9b0fb..4eb37bafa0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
@@ -14,8 +14,19 @@
#define UIA_SelectionPattern2Id 10034
#define UIA_IsReadOnlyAttributeId 40015
#define UIA_StrikethroughStyleAttributeId 40026
+#define UIA_StyleIdAttributeId 40034
#define UIA_CaretPositionAttributeId 40038
+#define StyleId_Heading1 70001
+#define StyleId_Heading2 70002
+#define StyleId_Heading3 70003
+#define StyleId_Heading4 70004
+#define StyleId_Heading5 70005
+#define StyleId_Heading6 70006
+#define StyleId_Heading7 70007
+#define StyleId_Heading8 70008
+#define StyleId_Heading9 70009
+
enum CaretPosition {
CaretPosition_Unknown = 0,
CaretPosition_EndOfLine = 1,
diff --git a/src/plugins/platforms/xcb/CMakeLists.txt b/src/plugins/platforms/xcb/CMakeLists.txt
index e8fb442dd4..4fa6c1e978 100644
--- a/src/plugins/platforms/xcb/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/CMakeLists.txt
@@ -146,6 +146,10 @@ qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_fontconfig AND QT_F
if(QT_FEATURE_system_xcb_xinput)
qt_internal_extend_target(XcbQpaPrivate LIBRARIES XCB::XINPUT)
else()
+ qt_internal_extend_target(XcbQpaPrivate
+ ATTRIBUTION_FILE_DIR_PATHS
+ ../../../3rdparty/xcb
+ )
set(xinput_source "${PROJECT_SOURCE_DIR}/src/3rdparty/xcb/libxcb/xinput.c")
set_source_files_properties(
"${xinput_source}"
@@ -164,7 +168,7 @@ endif()
qt_internal_add_plugin(QXcbIntegrationPlugin
OUTPUT_NAME qxcb
PLUGIN_TYPE platforms
- DEFAULT_IF ${QT_QPA_DEFAULT_PLATFORM} MATCHES xcb
+ DEFAULT_IF "xcb" IN_LIST QT_QPA_PLATFORMS
SOURCES
qxcbmain.cpp
DEFINES
diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
index c6492f02ae..8e2b3aed22 100644
--- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
+++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegration.h
@@ -14,7 +14,7 @@ class QPlatformOffscreenSurface;
class QOffscreenSurface;
class QXcbNativeInterfaceHandler;
-Q_DECLARE_EXPORTED_LOGGING_CATEGORY(lcQpaGl, Q_XCB_EXPORT)
+QT_DECLARE_EXPORTED_QT_LOGGING_CATEGORY(lcQpaGl, Q_XCB_EXPORT)
class Q_XCB_EXPORT QXcbGlIntegration
{
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index 40e2f47354..77157595b8 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -61,7 +61,7 @@ protected:
// get the list of targets from the current clipboard owner - we do this
// once so that multiple calls to this function don't require multiple
// server round trips...
- that->format_atoms = m_clipboard->getDataInFormat(modeAtom, m_clipboard->atom(QXcbAtom::AtomTARGETS));
+ that->format_atoms = m_clipboard->getDataInFormat(modeAtom, m_clipboard->atom(QXcbAtom::AtomTARGETS)).value_or(QByteArray());
if (format_atoms.size() > 0) {
const xcb_atom_t *targets = (const xcb_atom_t *) format_atoms.data();
@@ -91,7 +91,7 @@ protected:
{
auto requestedType = type;
if (fmt.isEmpty() || isEmpty())
- return QByteArray();
+ return QVariant();
(void)formats(); // trigger update of format list
@@ -108,7 +108,11 @@ protected:
if (fmtatom == 0)
return QVariant();
- return mimeConvertToFormat(m_clipboard->connection(), fmtatom, m_clipboard->getDataInFormat(modeAtom, fmtatom), fmt, requestedType, hasUtf8);
+ const std::optional<QByteArray> result = m_clipboard->getDataInFormat(modeAtom, fmtatom);
+ if (!result.has_value())
+ return QVariant();
+
+ return mimeConvertToFormat(m_clipboard->connection(), fmtatom, result.value(), fmt, requestedType, hasUtf8);
}
private:
@@ -776,7 +780,7 @@ xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t window, i
return nullptr;
}
-QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm)
+std::optional<QByteArray> QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm)
{
QByteArray buf;
QByteArray tmp_buf;
@@ -841,17 +845,16 @@ QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb
// could consider next request to be still part of this timed out request
setRequestor(0);
- return QByteArray();
+ return std::nullopt;
}
-QByteArray QXcbClipboard::getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtAtom)
+std::optional<QByteArray> QXcbClipboard::getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtAtom)
{
return getSelection(modeAtom, fmtAtom, atom(QXcbAtom::Atom_QT_SELECTION));
}
-QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t time)
+std::optional<QByteArray> QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t time)
{
- QByteArray buf;
xcb_window_t win = requestor();
if (time == 0) time = connection()->time();
@@ -866,17 +869,19 @@ QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target,
free(ge);
if (no_selection)
- return buf;
+ return std::nullopt;
xcb_atom_t type;
+ QByteArray buf;
if (clipboardReadProperty(win, property, true, &buf, nullptr, &type, nullptr)) {
if (type == atom(QXcbAtom::AtomINCR)) {
int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0;
- buf = clipboardReadIncrementalProperty(win, property, nbytes, false);
+ return clipboardReadIncrementalProperty(win, property, nbytes, false);
}
+ return buf;
}
- return buf;
+ return std::nullopt;
}
#endif // QT_NO_CLIPBOARD
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h
index 79c48a0af5..134daf4be7 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.h
+++ b/src/plugins/platforms/xcb/qxcbclipboard.h
@@ -67,13 +67,13 @@ public:
void handleXFixesSelectionRequest(xcb_xfixes_selection_notify_event_t *event);
bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format);
- QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm);
+ std::optional<QByteArray> clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm);
- QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom);
+ std::optional<QByteArray> getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom);
bool handlePropertyNotify(const xcb_generic_event_t *event);
- QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0);
+ std::optional<QByteArray> getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0);
int increment() const { return m_maxPropertyRequestDataBytes; }
int clipboardTimeout() const { return clipboard_timeout; }
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index 6e5dd770b9..71335444e9 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -17,7 +17,6 @@
#include <qguiapplication.h>
#include <qrect.h>
#include <qpainter.h>
-#include <qtimer.h>
#include <qpa/qwindowsysteminterface.h>
@@ -1306,32 +1305,33 @@ QVariant QXcbDropData::retrieveData_sys(const QString &mimetype, QMetaType reque
QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QMetaType requestedType) const
{
- QByteArray result;
-
QXcbConnection *c = drag->connection();
QXcbWindow *xcb_window = c->platformWindowFromId(drag->xdnd_dragsource);
if (xcb_window && drag->currentDrag() && xcb_window->window()->type() != Qt::Desktop) {
QMimeData *data = drag->currentDrag()->mimeData();
if (data->hasFormat(QLatin1StringView(format)))
- result = data->data(QLatin1StringView(format));
- return result;
+ return data->data(QLatin1StringView(format));
+ return QVariant();
}
QList<xcb_atom_t> atoms = drag->xdnd_types;
bool hasUtf8 = false;
xcb_atom_t a = mimeAtomForFormat(c, QLatin1StringView(format), requestedType, atoms, &hasUtf8);
if (a == XCB_NONE)
- return result;
+ return QVariant();
#ifndef QT_NO_CLIPBOARD
if (c->selectionOwner(c->atom(QXcbAtom::AtomXdndSelection)) == XCB_NONE)
- return result; // should never happen?
+ return QVariant(); // should never happen?
xcb_atom_t xdnd_selection = c->atom(QXcbAtom::AtomXdndSelection);
- result = c->clipboard()->getSelection(xdnd_selection, a, xdnd_selection, drag->targetTime());
+ const std::optional<QByteArray> result = c->clipboard()->getSelection(xdnd_selection, a, xdnd_selection, drag->targetTime());
+ if (!result.has_value())
+ return QVariant();
+ return mimeConvertToFormat(c, a, result.value(), QLatin1StringView(format), requestedType, hasUtf8);
+#else
+ return QVariant();
#endif
-
- return mimeConvertToFormat(c, a, result, QLatin1StringView(format), requestedType, hasUtf8);
}
bool QXcbDropData::hasFormat_sys(const QString &format) const
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 06f4b66edb..0ce337726e 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -23,6 +23,7 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
: QXcbObject(connection)
, m_screen(screen)
, m_number(number)
+ , m_xSettings(new QXcbXSettings(this))
{
const QByteArray cmAtomName = "_NET_WM_CM_S" + QByteArray::number(m_number);
m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
@@ -129,10 +130,6 @@ void QXcbVirtualDesktop::setPrimaryScreen(QPlatformScreen *s)
QXcbXSettings *QXcbVirtualDesktop::xSettings() const
{
- if (!m_xSettings) {
- QXcbVirtualDesktop *self = const_cast<QXcbVirtualDesktop *>(this);
- self->m_xSettings = new QXcbXSettings(self);
- }
return m_xSettings;
}
diff --git a/src/plugins/sqldrivers/.cmake.conf b/src/plugins/sqldrivers/.cmake.conf
index 10bc1fd407..6d83b084f7 100644
--- a/src/plugins/sqldrivers/.cmake.conf
+++ b/src/plugins/sqldrivers/.cmake.conf
@@ -1 +1 @@
-set(QT_REPO_MODULE_VERSION "6.8.0")
+set(QT_REPO_MODULE_VERSION "6.9.0")
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
index f6eed5e227..44443aaacb 100644
--- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
+++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
@@ -3,11 +3,13 @@
#include "qsql_ibase_p.h"
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qendian.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qtimezone.h>
#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qdebug.h>
#include <QtCore/qlist.h>
+#include <QtCore/private/qlocale_tools_p.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmap.h>
#include <QtCore/qmutex.h>
@@ -41,6 +43,10 @@ using namespace Qt::StringLiterals;
#define blr_boolean_dtype blr_bool
#endif
+#if (defined(QT_SUPPORTS_INT128) || defined(QT_USE_MSVC_INT128)) && (FB_API_VER >= 40)
+#define IBASE_INT128_SUPPORTED
+#endif
+
constexpr qsizetype QIBaseChunkSize = SHRT_MAX / 2;
#if (FB_API_VER >= 40)
@@ -91,7 +97,9 @@ static void enlargeDA(XSQLDA *&sqlda, int n)
static void initDA(XSQLDA *sqlda)
{
for (int i = 0; i < sqlda->sqld; ++i) {
- switch (sqlda->sqlvar[i].sqltype & ~1) {
+ XSQLVAR &sqlvar = sqlda->sqlvar[i];
+ const auto sqltype = (sqlvar.sqltype & ~1);
+ switch (sqltype) {
case SQL_INT64:
case SQL_LONG:
case SQL_SHORT:
@@ -100,32 +108,35 @@ static void initDA(XSQLDA *sqlda)
case SQL_TIMESTAMP:
#if (FB_API_VER >= 40)
case SQL_TIMESTAMP_TZ:
+#ifdef IBASE_INT128_SUPPORTED
+ case SQL_INT128:
+#endif
#endif
case SQL_TYPE_TIME:
case SQL_TYPE_DATE:
case SQL_TEXT:
case SQL_BLOB:
case SQL_BOOLEAN:
- sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen];
+ sqlvar.sqldata = new char[sqlvar.sqllen];
break;
case SQL_ARRAY:
- sqlda->sqlvar[i].sqldata = new char[sizeof(ISC_QUAD)];
- memset(sqlda->sqlvar[i].sqldata, 0, sizeof(ISC_QUAD));
+ sqlvar.sqldata = new char[sizeof(ISC_QUAD)];
+ memset(sqlvar.sqldata, 0, sizeof(ISC_QUAD));
break;
case SQL_VARYING:
- sqlda->sqlvar[i].sqldata = new char[sqlda->sqlvar[i].sqllen + sizeof(short)];
+ sqlvar.sqldata = new char[sqlvar.sqllen + sizeof(short)];
break;
default:
// not supported - do not bind.
- sqlda->sqlvar[i].sqldata = 0;
- qCWarning(lcIbase, "initDA: unknown sqltype: %d", sqlda->sqlvar[i].sqltype & ~1);
+ sqlvar.sqldata = 0;
+ qCWarning(lcIbase, "initDA: unknown sqltype: %d", sqltype);
break;
}
- if (sqlda->sqlvar[i].sqltype & 1) {
- sqlda->sqlvar[i].sqlind = new short[1];
- *(sqlda->sqlvar[i].sqlind) = 0;
+ if (sqlvar.sqltype & 1) {
+ sqlvar.sqlind = new short[1];
+ *(sqlvar.sqlind) = 0;
} else {
- sqlda->sqlvar[i].sqlind = 0;
+ sqlvar.sqlind = 0;
}
}
}
@@ -190,6 +201,10 @@ static QMetaType::Type qIBaseTypeName2(int iType, bool hasScale)
return (hasScale ? QMetaType::Double : QMetaType::Int);
case SQL_INT64:
return (hasScale ? QMetaType::Double : QMetaType::LongLong);
+#ifdef IBASE_INT128_SUPPORTED
+ case SQL_INT128:
+ return (hasScale ? QMetaType::Double : QMetaType::LongLong);
+#endif
case SQL_FLOAT:
case SQL_DOUBLE:
return QMetaType::Double;
@@ -215,42 +230,35 @@ static QMetaType::Type qIBaseTypeName2(int iType, bool hasScale)
return QMetaType::UnknownType;
}
-static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
+// InterBase and FireBird use the modified Julian Date with 1858-11-17 as day 0.
+static constexpr auto s_ibaseBaseDate = QDate::fromJulianDay(2400001);
+
+static inline ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
{
- static const QTime midnight(0, 0, 0, 0);
- static const QDate basedate(1858, 11, 17);
ISC_TIMESTAMP ts;
- ts.timestamp_time = midnight.msecsTo(dt.time()) * 10;
- ts.timestamp_date = basedate.daysTo(dt.date());
+ ts.timestamp_time = dt.time().msecsSinceStartOfDay() * 10;
+ ts.timestamp_date = s_ibaseBaseDate.daysTo(dt.date());
return ts;
}
-static QDateTime fromTimeStamp(char *buffer)
+static inline QDateTime fromTimeStamp(const char *buffer)
{
- static const QDate bd(1858, 11, 17);
- QTime t(0, 0);
- QDate d;
-
// have to demangle the structure ourselves because isc_decode_time
// strips the msecs
- auto timebuf = reinterpret_cast<ISC_TIMESTAMP*>(buffer);
- t = t.addMSecs(static_cast<int>(timebuf->timestamp_time / 10));
- d = bd.addDays(timebuf->timestamp_date);
+ auto timebuf = reinterpret_cast<const ISC_TIMESTAMP *>(buffer);
+ const QTime t = QTime::fromMSecsSinceStartOfDay(timebuf->timestamp_time / 10);
+ const QDate d = s_ibaseBaseDate.addDays(timebuf->timestamp_date);
return QDateTime(d, t);
}
#if (FB_API_VER >= 40)
-QDateTime fromTimeStampTz(char *buffer)
+static inline QDateTime fromTimeStampTz(const char *buffer)
{
- static const QDate bd(1858, 11, 17);
- QTime t(0, 0);
- QDate d;
-
// have to demangle the structure ourselves because isc_decode_time
// strips the msecs
- auto timebuf = reinterpret_cast<ISC_TIMESTAMP_TZ*>(buffer);
- t = t.addMSecs(static_cast<int>(timebuf->utc_timestamp.timestamp_time / 10));
- d = bd.addDays(timebuf->utc_timestamp.timestamp_date);
+ auto timebuf = reinterpret_cast<const ISC_TIMESTAMP_TZ *>(buffer);
+ const QTime t = QTime::fromMSecsSinceStartOfDay(timebuf->utc_timestamp.timestamp_time / 10);
+ const QDate d = s_ibaseBaseDate.addDays(timebuf->utc_timestamp.timestamp_date);
quint16 fpTzID = timebuf->time_zone;
QByteArray timeZoneName = qFbTzIdToIanaIdMap()->value(fpTzID);
@@ -260,53 +268,40 @@ QDateTime fromTimeStampTz(char *buffer)
return {};
}
-ISC_TIMESTAMP_TZ toTimeStampTz(const QDateTime &dt)
+static inline ISC_TIMESTAMP_TZ toTimeStampTz(const QDateTime &dt)
{
- static const QTime midnight(0, 0, 0, 0);
- static const QDate basedate(1858, 11, 17);
ISC_TIMESTAMP_TZ ts;
- ts.utc_timestamp.timestamp_time = midnight.msecsTo(dt.time()) * 10;
- ts.utc_timestamp.timestamp_date = basedate.daysTo(dt.date());
+ ts.utc_timestamp.timestamp_time = dt.time().msecsSinceStartOfDay() * 10;
+ ts.utc_timestamp.timestamp_date = s_ibaseBaseDate.daysTo(dt.date());
ts.time_zone = qIanaIdToFbTzIdMap()->value(dt.timeZone().id().simplified(), 0);
return ts;
}
#endif
-static ISC_TIME toTime(QTime t)
+static inline ISC_TIME toTime(QTime t)
{
- static const QTime midnight(0, 0, 0, 0);
- return (ISC_TIME)midnight.msecsTo(t) * 10;
+ return t.msecsSinceStartOfDay() * 10;
}
-static QTime fromTime(char *buffer)
+static inline QTime fromTime(const char *buffer)
{
- QTime t(0, 0);
// have to demangle the structure ourselves because isc_decode_time
// strips the msecs
- t = t.addMSecs(int((*(ISC_TIME*)buffer) / 10));
-
- return t;
+ const auto timebuf = reinterpret_cast<const ISC_TIME *>(buffer);
+ return QTime::fromMSecsSinceStartOfDay(*timebuf / 10);
}
-static ISC_DATE toDate(QDate t)
+static inline ISC_DATE toDate(QDate t)
{
- static const QDate basedate(1858, 11, 17);
- ISC_DATE date;
-
- date = basedate.daysTo(t);
- return date;
-}
+ return s_ibaseBaseDate.daysTo(t);
+ }
-static QDate fromDate(char *buffer)
+static inline QDate fromDate(const char *buffer)
{
- static const QDate bd(1858, 11, 17);
- QDate d;
-
// have to demangle the structure ourselves because isc_decode_time
// strips the msecs
- d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date));
-
- return d;
+ const auto tsbuf = reinterpret_cast<const ISC_TIMESTAMP *>(buffer);
+ return s_ibaseBaseDate.addDays(int(tsbuf->timestamp_date));
}
struct QIBaseEventBuffer {
@@ -347,21 +342,14 @@ public:
QSqlQuery qry(q->createResult());
qry.setForwardOnly(true);
qry.exec(QString("select * from RDB$TIME_ZONES"_L1));
- if (qry.lastError().type()) {
- q->setLastError(QSqlError(
- QCoreApplication::translate("QIBaseDriver",
- "failed to query time zone mapping from system table"),
- qry.lastError().databaseText(),
- QSqlError::StatementError,
- qry.lastError().nativeErrorCode()));
-
+ if (qry.lastError().isValid()) {
+ qCInfo(lcIbase) << "Table 'RDB$TIME_ZONES' not found - not timezone support available";
return;
}
while (qry.next()) {
- auto record = qry.record();
- quint16 fbTzId = record.value(0).value<quint16>();
- QByteArray ianaId = record.value(1).toByteArray().simplified();
+ quint16 fbTzId = qry.value(0).value<quint16>();
+ QByteArray ianaId = qry.value(1).toByteArray().simplified();
qFbTzIdToIanaIdMap()->insert(fbTzId, ianaId);
qIanaIdToFbTzIdMap()->insert(ianaId, fbTzId);
}
@@ -408,6 +396,32 @@ protected:
QSqlRecord record() const override;
template<typename T>
+ static QString numberToHighPrecision(T val, int scale)
+ {
+ const bool negative = val < 0;
+ QString number;
+#ifdef IBASE_INT128_SUPPORTED
+ if constexpr (std::is_same_v<qinternalint128, T>) {
+ number = negative ? qint128toBasicLatin(val * -1)
+ : qint128toBasicLatin(val);
+ } else
+#endif
+ number = negative ? QString::number(qAbs(val))
+ : QString::number(val);
+ auto len = number.size();
+ scale *= -1;
+ if (scale >= len) {
+ number = QString(scale - len + 1, u'0') + number;
+ len = number.size();
+ }
+ const auto sepPos = len - scale;
+ number = number.left(sepPos) + u'.' + number.mid(sepPos);
+ if (negative)
+ number = u'-' + number;
+ return number;
+ }
+
+ template<typename T>
QVariant applyScale(T val, int scale) const
{
if (scale >= 0)
@@ -420,28 +434,36 @@ protected:
return QVariant(qint64(val * pow(10.0, scale)));
case QSql::LowPrecisionDouble:
return QVariant(double(val * pow(10.0, scale)));
- case QSql::HighPrecision: {
- const bool negative = val < 0;
- QString number;
- if constexpr (std::is_signed_v<T> || negative)
- number = QString::number(qAbs(val));
- else
- number = QString::number(val);
- auto len = number.size();
- scale *= -1;
- if (scale >= len) {
- number = QString(scale - len + 1, u'0') + number;
- len = number.size();
- }
- const auto sepPos = len - scale;
- number = number.left(sepPos) + u'.' + number.mid(sepPos);
- if (negative)
- number = u'-' + number;
- return QVariant(number);
- }
+ case QSql::HighPrecision:
+ return QVariant(numberToHighPrecision(val, scale));
}
return QVariant(val);
}
+
+ template<typename T>
+ void setWithScale(const QVariant &val, int scale, char *data)
+ {
+ auto ptr = reinterpret_cast<T *>(data);
+ if (scale < 0) {
+ double d = floor(0.5 + val.toDouble() * pow(10.0, scale * -1));
+#ifdef IBASE_INT128_SUPPORTED
+ if constexpr (std::is_same_v<qinternalint128, T>) {
+ quint64 lower = quint64(d);
+ quint64 tmp = quint64(std::numeric_limits<quint32>::max()) + 1;
+ d /= tmp;
+ d /= tmp;
+ quint64 higher = quint64(d);
+ qinternalint128 result = higher;
+ result <<= 64;
+ result += lower;
+ *ptr = static_cast<T>(result);
+ } else
+#endif
+ *ptr = static_cast<T>(d);
+ }
+ else
+ *ptr = val.value<T>();
+ }
};
class QIBaseResultPrivate: public QSqlCachedResultPrivate
@@ -487,6 +509,7 @@ public:
XSQLDA *sqlda; // output sqlda
XSQLDA *inda; // input parameters
int queryType;
+ mutable QSqlRecord cachedRecord;
};
@@ -518,6 +541,7 @@ void QIBaseResultPrivate::cleanup()
delDA(inda);
queryType = -1;
+ cachedRecord.clear();
q->cleanup();
}
@@ -551,9 +575,8 @@ QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId)
return QVariant();
unsigned short len = 0;
- QByteArray ba;
- int chunkSize = QIBaseChunkSize;
- ba.resize(chunkSize);
+ constexpr auto chunkSize = QIBaseChunkSize;
+ QByteArray ba(chunkSize, Qt::Uninitialized);
qsizetype read = 0;
while (isc_get_segment(status, &handle, &len, chunkSize, ba.data() + read) == 0 || status[1] == isc_segment) {
read += len;
@@ -576,9 +599,10 @@ QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId)
}
template<typename T>
-static QList<QVariant> toList(char** buf, int count)
+static QList<QVariant> toList(const char **buf, int count)
{
QList<QVariant> res;
+ res.reserve(count);
for (int i = 0; i < count; ++i) {
res.append(*(T*)(*buf));
*buf += sizeof(T);
@@ -586,8 +610,8 @@ static QList<QVariant> toList(char** buf, int count)
return res;
}
-static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim,
- short* numElements, ISC_ARRAY_DESC *arrayDesc)
+static const char *readArrayBuffer(QList<QVariant>& list, const char *buffer, short curDim,
+ const short *numElements, ISC_ARRAY_DESC *arrayDesc)
{
const short dim = arrayDesc->array_desc_dimensions - 1;
const unsigned char dataType = arrayDesc->array_desc_dtype;
@@ -675,8 +699,9 @@ QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr)
if (!arr)
return list;
- QByteArray relname(sqlda->sqlvar[pos].relname, sqlda->sqlvar[pos].relname_length);
- QByteArray sqlname(sqlda->sqlvar[pos].sqlname, sqlda->sqlvar[pos].sqlname_length);
+ const XSQLVAR &sqlvar = sqlda->sqlvar[pos];
+ const auto relname = QByteArray::fromRawData(sqlvar.relname, sqlvar.relname_length);
+ const auto sqlname = QByteArray::fromRawData(sqlvar.sqlname, sqlvar.sqlname_length);
isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
@@ -684,19 +709,18 @@ QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr)
return list;
- int arraySize = 1, subArraySize;
+ int arraySize = 1;
short dimensions = desc.array_desc_dimensions;
QVarLengthArray<short> numElements(dimensions);
for(int i = 0; i < dimensions; ++i) {
- subArraySize = (desc.array_desc_bounds[i].array_bound_upper -
- desc.array_desc_bounds[i].array_bound_lower + 1);
+ short subArraySize = (desc.array_desc_bounds[i].array_bound_upper -
+ desc.array_desc_bounds[i].array_bound_lower + 1);
numElements[i] = subArraySize;
arraySize = subArraySize * arraySize;
}
ISC_LONG bufLen;
- QByteArray ba;
/* varying arrayelements are stored with 2 trailing null bytes
indicating the length of the string
*/
@@ -708,14 +732,13 @@ QVariant QIBaseResultPrivate::fetchArray(int pos, ISC_QUAD *arr)
bufLen = desc.array_desc_length * arraySize;
}
-
- ba.resize(int(bufLen));
+ QByteArray ba(bufLen, Qt::Uninitialized);
isc_array_get_slice(status, &ibase, &trans, arr, &desc, ba.data(), &bufLen);
if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not get array data"),
QSqlError::StatementError))
return list;
- readArrayBuffer(list, ba.data(), 0, numElements.data(), &desc);
+ readArrayBuffer(list, ba.constData(), 0, numElements.constData(), &desc);
return QVariant(list);
}
@@ -752,16 +775,16 @@ static char* qFillBufferWithString(char *buffer, const QString& string,
if (str.length() < buflen)
buflen = str.length();
if (array) { // interbase stores varying arrayelements different than normal varying elements
- memcpy(buffer, str.data(), buflen);
+ memcpy(buffer, str.constData(), buflen);
memset(buffer + buflen, 0, tmpBuflen - buflen);
} else {
*(short*)buffer = buflen; // first two bytes is the length
- memcpy(buffer + sizeof(short), str.data(), buflen);
+ memcpy(buffer + sizeof(short), str.constData(), buflen);
}
buffer += tmpBuflen;
} else {
str = str.leftJustified(buflen, ' ', true);
- memcpy(buffer, str.data(), buflen);
+ memcpy(buffer, str.constData(), buflen);
buffer += buflen;
}
return buffer;
@@ -778,9 +801,10 @@ static char* createArrayBuffer(char *buffer, const QList<QVariant> &list,
bounds[curDim].array_bound_lower + 1);
if (list.size() != elements) { // size mismatch
- error = "Expected size: %1. Supplied size: %2"_L1;
- error = "Array size mismatch. Fieldname: %1 "_L1
- + error.arg(elements).arg(list.size());
+ error = QCoreApplication::translate(
+ "QIBaseResult",
+ "Array size mismatch. Field name: %3, expected size: %1. Supplied size: %2")
+ .arg(elements).arg(list.size());
return 0;
}
@@ -788,7 +812,9 @@ static char* createArrayBuffer(char *buffer, const QList<QVariant> &list,
for (const auto &elem : list) {
if (elem.typeId() != QMetaType::QVariantList) { // dimensions mismatch
- error = "Array dimensons mismatch. Fieldname: %1"_L1;
+ error = QCoreApplication::translate(
+ "QIBaseResult",
+ "Array dimensions mismatch. Field name: %1");
return 0;
}
@@ -869,11 +895,12 @@ bool QIBaseResultPrivate::writeArray(qsizetype column, const QList<QVariant> &li
{
Q_Q(QIBaseResult);
QString error;
- ISC_QUAD *arrayId = (ISC_QUAD*) inda->sqlvar[column].sqldata;
ISC_ARRAY_DESC desc;
- QByteArray relname(inda->sqlvar[column].relname, inda->sqlvar[column].relname_length);
- QByteArray sqlname(inda->sqlvar[column].sqlname, inda->sqlvar[column].sqlname_length);
+ XSQLVAR &sqlvar = inda->sqlvar[column];
+ ISC_QUAD *arrayId = (ISC_QUAD*) sqlvar.sqldata;
+ const auto relname = QByteArray::fromRawData(sqlvar.relname, sqlvar.relname_length);
+ const auto sqlname = QByteArray::fromRawData(sqlvar.sqlname, sqlvar.sqlname_length);
isc_array_lookup_bounds(status, &ibase, &trans, relname.data(), sqlname.data(), &desc);
if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Could not find array"),
@@ -897,20 +924,21 @@ bool QIBaseResultPrivate::writeArray(qsizetype column, const QList<QVariant> &li
desc.array_desc_length += 2;
bufLen = desc.array_desc_length * arraySize;
- QByteArray ba;
- ba.resize(int(bufLen));
+ QByteArray ba(bufLen, Qt::Uninitialized);
if (list.size() > arraySize) {
- error = "Array size mismatch: size of %1 is %2, size of provided list is %3"_L1;
+ error = QCoreApplication::translate(
+ "QIBaseResult",
+ "Array size mismatch: size of %1 is %2, size of provided list is %3");
error = error.arg(QLatin1StringView(sqlname)).arg(arraySize).arg(list.size());
- q->setLastError(QSqlError(error, ""_L1, QSqlError::StatementError));
+ q->setLastError(QSqlError(error, {}, QSqlError::StatementError));
return false;
}
if (!createArrayBuffer(ba.data(), list,
- qIBaseTypeName(desc.array_desc_dtype, inda->sqlvar[column].sqlscale < 0),
+ qIBaseTypeName(desc.array_desc_dtype, sqlvar.sqlscale < 0),
0, &desc, error)) {
- q->setLastError(QSqlError(error.arg(QLatin1StringView(sqlname)), ""_L1,
+ q->setLastError(QSqlError(error.arg(QLatin1StringView(sqlname)), {},
QSqlError::StatementError));
return false;
}
@@ -1078,79 +1106,73 @@ bool QIBaseResult::exec()
return false;
}
for (qsizetype para = 0; para < values.count(); ++para) {
- if (!d->inda->sqlvar[para].sqldata)
+ const XSQLVAR &sqlvar = d->inda->sqlvar[para];
+ if (!sqlvar.sqldata)
// skip unknown datatypes
continue;
const QVariant &val = values[para];
- if (d->inda->sqlvar[para].sqltype & 1) {
+ if (sqlvar.sqltype & 1) {
if (QSqlResultPrivate::isVariantNull(val)) {
// set null indicator
- *(d->inda->sqlvar[para].sqlind) = -1;
+ *(sqlvar.sqlind) = -1;
// and set the value to 0, otherwise it would count as empty string.
// it seems to be working with just setting sqlind to -1
- //*((char*)d->inda->sqlvar[para].sqldata) = 0;
+ //*((char*)sqlvar.sqldata) = 0;
continue;
}
// a value of 0 means non-null.
- *(d->inda->sqlvar[para].sqlind) = 0;
+ *(sqlvar.sqlind) = 0;
} else {
if (QSqlResultPrivate::isVariantNull(val)) {
qCWarning(lcIbase) << "QIBaseResult::exec: Null value replaced by default (zero)"_L1
- << "value for type of column"_L1 << d->inda->sqlvar[para].ownname
+ << "value for type of column"_L1 << sqlvar.ownname
<< ", which is not nullable."_L1;
}
}
- switch(d->inda->sqlvar[para].sqltype & ~1) {
+ const auto sqltype = sqlvar.sqltype & ~1;
+ switch (sqltype) {
case SQL_INT64:
- if (d->inda->sqlvar[para].sqlscale < 0)
- *((qint64*)d->inda->sqlvar[para].sqldata) =
- (qint64)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
- else
- *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong();
+ setWithScale<qint64>(val, sqlvar.sqlscale, sqlvar.sqldata);
+ break;
+#ifdef IBASE_INT128_SUPPORTED
+ case SQL_INT128:
+ setWithScale<qinternalint128>(val, sqlvar.sqlscale,
+ sqlvar.sqldata);
break;
+#endif
case SQL_LONG:
- if (d->inda->sqlvar[para].sqllen == 4) {
- if (d->inda->sqlvar[para].sqlscale < 0)
- *((qint32*)d->inda->sqlvar[para].sqldata) =
- (qint32)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
- else
- *((qint32*)d->inda->sqlvar[para].sqldata) = (qint32)val.toInt();
- } else {
- *((qint64*)d->inda->sqlvar[para].sqldata) = val.toLongLong();
- }
+ if (sqlvar.sqllen == 4)
+ setWithScale<qint32>(val, sqlvar.sqlscale, sqlvar.sqldata);
+ else
+ setWithScale<qint64>(val, 0, sqlvar.sqldata);
break;
case SQL_SHORT:
- if (d->inda->sqlvar[para].sqlscale < 0)
- *((short*)d->inda->sqlvar[para].sqldata) =
- (short)floor(0.5 + val.toDouble() * pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
- else
- *((short*)d->inda->sqlvar[para].sqldata) = (short)val.toInt();
+ setWithScale<qint16>(val, sqlvar.sqlscale, sqlvar.sqldata);
break;
case SQL_FLOAT:
- *((float*)d->inda->sqlvar[para].sqldata) = (float)val.toDouble();
+ *((float*)sqlvar.sqldata) = val.toFloat();
break;
case SQL_DOUBLE:
- *((double*)d->inda->sqlvar[para].sqldata) = val.toDouble();
+ *((double*)sqlvar.sqldata) = val.toDouble();
break;
case SQL_TIMESTAMP:
- *((ISC_TIMESTAMP*)d->inda->sqlvar[para].sqldata) = toTimeStamp(val.toDateTime());
+ *((ISC_TIMESTAMP*)sqlvar.sqldata) = toTimeStamp(val.toDateTime());
break;
#if (FB_API_VER >= 40)
case SQL_TIMESTAMP_TZ:
- *((ISC_TIMESTAMP_TZ*)d->inda->sqlvar[para].sqldata) = toTimeStampTz(val.toDateTime());
+ *((ISC_TIMESTAMP_TZ*)sqlvar.sqldata) = toTimeStampTz(val.toDateTime());
break;
#endif
case SQL_TYPE_TIME:
- *((ISC_TIME*)d->inda->sqlvar[para].sqldata) = toTime(val.toTime());
+ *((ISC_TIME*)sqlvar.sqldata) = toTime(val.toTime());
break;
case SQL_TYPE_DATE:
- *((ISC_DATE*)d->inda->sqlvar[para].sqldata) = toDate(val.toDate());
+ *((ISC_DATE*)sqlvar.sqldata) = toDate(val.toDate());
break;
case SQL_VARYING:
case SQL_TEXT:
- qFillBufferWithString(d->inda->sqlvar[para].sqldata, val.toString(),
- d->inda->sqlvar[para].sqllen,
- (d->inda->sqlvar[para].sqltype & ~1) == SQL_VARYING, false);
+ qFillBufferWithString(sqlvar.sqldata, val.toString(), sqlvar.sqllen,
+ sqltype == SQL_VARYING, false);
break;
case SQL_BLOB:
ok &= d->writeBlob(para, val.toByteArray());
@@ -1159,11 +1181,11 @@ bool QIBaseResult::exec()
ok &= d->writeArray(para, val.toList());
break;
case SQL_BOOLEAN:
- *((bool*)d->inda->sqlvar[para].sqldata) = val.toBool();
+ *((bool*)sqlvar.sqldata) = val.toBool();
break;
default:
qCWarning(lcIbase, "QIBaseResult::exec: Unknown datatype %d",
- d->inda->sqlvar[para].sqltype & ~1);
+ sqltype);
break;
}
}
@@ -1241,15 +1263,12 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
for (int i = 0; i < d->sqlda->sqld; ++i) {
int idx = rowIdx + i;
- char *buf = d->sqlda->sqlvar[i].sqldata;
- int size = d->sqlda->sqlvar[i].sqllen;
- Q_ASSERT(buf);
+ const XSQLVAR &sqlvar = d->sqlda->sqlvar[i];
- if ((d->sqlda->sqlvar[i].sqltype & 1) && *d->sqlda->sqlvar[i].sqlind) {
+ if ((sqlvar.sqltype & 1) && *sqlvar.sqlind) {
// null value
QVariant v;
- v.convert(QMetaType(qIBaseTypeName2(d->sqlda->sqlvar[i].sqltype,
- d->sqlda->sqlvar[i].sqlscale < 0)));
+ v.convert(QMetaType(qIBaseTypeName2(sqlvar.sqltype, sqlvar.sqlscale < 0)));
if (v.userType() == QMetaType::Double) {
switch(numericalPrecisionPolicy()) {
case QSql::LowPrecisionInt32:
@@ -1270,29 +1289,44 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
continue;
}
- switch(d->sqlda->sqlvar[i].sqltype & ~1) {
+ const char *buf = sqlvar.sqldata;
+ int size = sqlvar.sqllen;
+ Q_ASSERT(buf);
+ const auto sqltype = sqlvar.sqltype & ~1;
+ switch (sqltype) {
case SQL_VARYING:
// pascal strings - a short with a length information followed by the data
row[idx] = QString::fromUtf8(buf + sizeof(short), *(short*)buf);
break;
case SQL_INT64: {
- Q_ASSERT(d->sqlda->sqlvar[i].sqllen == sizeof(qint64));
+ Q_ASSERT(sqlvar.sqllen == sizeof(qint64));
const auto val = *(qint64 *)buf;
- const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ const auto scale = sqlvar.sqlscale;
row[idx] = applyScale(val, scale);
break;
}
+#ifdef IBASE_INT128_SUPPORTED
+ case SQL_INT128: {
+ Q_ASSERT(sqlvar.sqllen == sizeof(qinternalint128));
+ const qinternalint128 val128 = qFromUnaligned<qinternalint128>(buf);
+ const auto scale = sqlvar.sqlscale;
+ row[idx] = numberToHighPrecision(val128, scale);
+ if (numericalPrecisionPolicy() != QSql::HighPrecision)
+ row[idx] = applyScale(row[idx].toDouble(), 0);
+ break;
+ }
+#endif
case SQL_LONG:
- if (d->sqlda->sqlvar[i].sqllen == 4) {
+ if (sqlvar.sqllen == 4) {
const auto val = *(qint32 *)buf;
- const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ const auto scale = sqlvar.sqlscale;
row[idx] = applyScale(val, scale);
} else
row[idx] = QVariant(*(qint64*)buf);
break;
case SQL_SHORT: {
const auto val = *(short *)buf;
- const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ const auto scale = sqlvar.sqlscale;
row[idx] = applyScale(val, scale);
break;
}
@@ -1330,8 +1364,7 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
#endif
default:
// unknown type - don't even try to fetch
- qCWarning(lcIbase, "gotoNext: unknown sqltype: %d",
- d->sqlda->sqlvar[i].sqltype & ~1);
+ qCWarning(lcIbase, "gotoNext: unknown sqltype: %d", sqltype);
row[idx] = QVariant();
break;
}
@@ -1449,13 +1482,14 @@ int QIBaseResult::numRowsAffected()
QSqlRecord QIBaseResult::record() const
{
Q_D(const QIBaseResult);
- QSqlRecord rec;
if (!isActive() || !d->sqlda)
- return rec;
+ return {};
+
+ if (!d->cachedRecord.isEmpty())
+ return d->cachedRecord;
- XSQLVAR v;
for (int i = 0; i < d->sqlda->sqld; ++i) {
- v = d->sqlda->sqlvar[i];
+ const XSQLVAR &v = d->sqlda->sqlvar[i];
QSqlField f(QString::fromLatin1(v.aliasname, v.aliasname_length).simplified(),
QMetaType(qIBaseTypeName2(v.sqltype, v.sqlscale < 0)),
QString::fromLatin1(v.relname, v.relname_length));
@@ -1481,9 +1515,9 @@ QSqlRecord QIBaseResult::record() const
f.setRequiredStatus(q.value(3).toBool() ? QSqlField::Required : QSqlField::Optional);
}
}
- rec.append(f);
+ d->cachedRecord.append(f);
}
- return rec;
+ return d->cachedRecord;
}
QVariant QIBaseResult::handle() const
@@ -1574,18 +1608,18 @@ bool QIBaseDriver::open(const QString &db,
ba.append(char(isc_dpb_version1));
ba.append(char(isc_dpb_user_name));
ba.append(char(usr.length()));
- ba.append(usr.data(), usr.length());
+ ba.append(usr.constData(), usr.length());
ba.append(char(isc_dpb_password));
ba.append(char(pass.length()));
- ba.append(pass.data(), pass.length());
+ ba.append(pass.constData(), pass.length());
ba.append(char(isc_dpb_lc_ctype));
ba.append(char(enc.length()));
- ba.append(enc.data(), enc.length());
+ ba.append(enc.constData(), enc.length());
if (!role.isEmpty()) {
ba.append(char(isc_dpb_sql_role_name));
ba.append(char(role.length()));
- ba.append(role.data(), role.length());
+ ba.append(role.constData(), role.length());
}
QString portString;
@@ -1597,7 +1631,7 @@ bool QIBaseDriver::open(const QString &db,
ldb += host + portString + u':';
ldb += db;
isc_attach_database(d->status, 0, const_cast<char *>(ldb.toLocal8Bit().constData()),
- &d->ibase, ba.size(), ba.data());
+ &d->ibase, ba.size(), ba.constData());
if (d->isError(QT_TRANSLATE_NOOP("QIBaseDriver", "Error opening database"),
QSqlError::ConnectionError)) {
setOpenError(true);
@@ -1891,7 +1925,7 @@ bool QIBaseDriver::subscribeToNotification(const QString &name)
eBuffer->resultBuffer);
if (status[0] == 1 && status[1]) {
- setLastError(QSqlError(QString::fromLatin1("Could not subscribe to event notifications for %1.").arg(name)));
+ setLastError(QSqlError(tr("Could not subscribe to event notifications for %1.").arg(name)));
d->eventBuffers.remove(name);
qFreeEventBuffer(eBuffer);
return false;
@@ -1920,7 +1954,7 @@ bool QIBaseDriver::unsubscribeFromNotification(const QString &name)
isc_cancel_events(status, &d->ibase, &eBuffer->eventId);
if (status[0] == 1 && status[1]) {
- setLastError(QSqlError(QString::fromLatin1("Could not unsubscribe from event notifications for %1.").arg(name)));
+ setLastError(QSqlError(tr("Could not unsubscribe from event notifications for %1.").arg(name)));
return false;
}
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
index 976911d458..77137f3b3c 100644
--- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
+++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
@@ -27,7 +27,7 @@
QT_BEGIN_NAMESPACE
-static Q_LOGGING_CATEGORY(lcOdbc, "qt.sql.odbc")
+Q_STATIC_LOGGING_CATEGORY(lcOdbc, "qt.sql.odbc")
using namespace Qt::StringLiterals;
diff --git a/src/plugins/sqldrivers/sqlite/CMakeLists.txt b/src/plugins/sqldrivers/sqlite/CMakeLists.txt
index 4203a5c437..e667034c2e 100644
--- a/src/plugins/sqldrivers/sqlite/CMakeLists.txt
+++ b/src/plugins/sqldrivers/sqlite/CMakeLists.txt
@@ -60,6 +60,8 @@ qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_system_sq
SQLITE_OMIT_COMPLETE
INCLUDE_DIRECTORIES
../../../3rdparty/sqlite
+ ATTRIBUTION_FILE_DIR_PATHS
+ ../../../3rdparty/sqlite
)
qt_internal_extend_target(QSQLiteDriverPlugin CONDITION CMAKE_BUILD_TYPE STREQUAL Release AND NOT QT_FEATURE_system_sqlite
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
index c574772fd7..05af02e156 100644
--- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
@@ -39,7 +39,7 @@ Q_DECLARE_METATYPE(sqlite3_stmt*)
QT_BEGIN_NAMESPACE
-static Q_LOGGING_CATEGORY(lcSqlite, "qt.sql.sqlite")
+Q_STATIC_LOGGING_CATEGORY(lcSqlite, "qt.sql.sqlite")
using namespace Qt::StringLiterals;
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index 3f57f284e6..226da495f4 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -21,6 +21,7 @@
#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/qpainterpath.h>
+#include <QtGui/qstylehints.h>
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/qpa/qplatformfontdatabase.h>
#include <QtGui/qpa/qplatformtheme.h>
@@ -160,7 +161,10 @@ const int pushButtonBevelRectOffsets[3] = {
QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
-bool isDarkMode() { return QGuiApplicationPrivate::platformTheme()->colorScheme() == Qt::ColorScheme::Dark; }
+static inline bool isDarkMode()
+{
+ return QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark;
+}
#if QT_CONFIG(tabwidget)
/*
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
index 784f491681..63663c74aa 100644
--- a/src/plugins/styles/modernwindows/qwindows11style.cpp
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -9,12 +9,15 @@
#include <qstyleoption.h>
#include <qpainter.h>
#include <QGraphicsDropShadowEffect>
+#include <QLatin1StringView>
#include <QtWidgets/qcombobox.h>
#include <QtWidgets/qcommandlinkbutton.h>
#include <QtWidgets/qgraphicsview.h>
#include <QtWidgets/qlistview.h>
#include <QtWidgets/qmenu.h>
+#if QT_CONFIG(mdiarea)
#include <QtWidgets/qmdiarea.h>
+#endif
#include <QtWidgets/qtextedit.h>
#include <QtWidgets/qtreeview.h>
@@ -25,6 +28,7 @@ QT_BEGIN_NAMESPACE
const static int topLevelRoundingRadius = 8; //Radius for toplevel items like popups for round corners
const static int secondLevelRoundingRadius = 4; //Radius for second level items like hovered menu item round corners
+constexpr QLatin1StringView originalWidthProperty("_q_windows11_style_original_width");
enum WINUI3Color {
subtleHighlightColor, //Subtle highlight based on alpha used for hovered elements
@@ -134,6 +138,8 @@ static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbut
*/
QWindows11Style::QWindows11Style() : QWindowsVistaStyle(*new QWindows11StylePrivate)
{
+ highContrastTheme = QGuiApplicationPrivate::styleHints->colorScheme() == Qt::ColorScheme::Unknown;
+ colorSchemeIndex = QGuiApplicationPrivate::styleHints->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
}
/*!
@@ -142,6 +148,8 @@ QWindows11Style::QWindows11Style() : QWindowsVistaStyle(*new QWindows11StylePriv
*/
QWindows11Style::QWindows11Style(QWindows11StylePrivate &dd) : QWindowsVistaStyle(dd)
{
+ highContrastTheme = QGuiApplicationPrivate::styleHints->colorScheme() == Qt::ColorScheme::Unknown;
+ colorSchemeIndex = QGuiApplicationPrivate::styleHints->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
}
/*!
@@ -1738,6 +1746,10 @@ int QWindows11Style::styleHint(StyleHint hint, const QStyleOption *opt,
return 0;
case QStyle::SH_ItemView_ShowDecorationSelected:
return 1;
+ case QStyle::SH_Slider_AbsoluteSetButtons:
+ return Qt::LeftButton;
+ case QStyle::SH_Slider_PageSetButtons:
+ return 0;
default:
return QWindowsVistaStyle::styleHint(hint, opt, widget, returnData);
}
@@ -2036,6 +2048,13 @@ void QWindows11Style::polish(QWidget* widget)
QLineEdit *le = cb->lineEdit();
le->setFrame(false);
}
+ } else if (widget->inherits("QAbstractSpinBox")) {
+ const int minWidth = 2 * 24 + 40;
+ const int originalWidth = widget->size().width();
+ if (originalWidth < minWidth) {
+ widget->resize(minWidth, widget->size().height());
+ widget->setProperty(originalWidthProperty.constData(), originalWidth);
+ }
} else if (widget->inherits("QAbstractButton") || widget->inherits("QToolButton")) {
widget->setAutoFillBackground(false);
} else if (qobject_cast<QGraphicsView *>(widget) && !qobject_cast<QTextEdit *>(widget)) {
@@ -2043,7 +2062,11 @@ void QWindows11Style::polish(QWidget* widget)
pal.setColor(QPalette::Base, pal.window().color());
widget->setPalette(pal);
} else if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget);
- scrollarea && !qobject_cast<QMdiArea *>(widget)) {
+ scrollarea
+#if QT_CONFIG(mdiarea)
+ && !qobject_cast<QMdiArea *>(widget)
+#endif
+ ) {
QPalette pal = scrollarea->viewport()->palette();
const QPalette originalPalette = pal;
pal.setColor(scrollarea->viewport()->backgroundRole(), Qt::transparent);
@@ -2062,11 +2085,22 @@ void QWindows11Style::unpolish(QWidget *widget)
{
QWindowsVistaStyle::unpolish(widget);
if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget);
- scrollarea && !qobject_cast<QMdiArea *>(widget)) {
+ scrollarea
+#if QT_CONFIG(mdiarea)
+ && !qobject_cast<QMdiArea *>(widget)
+#endif
+ ) {
const QPalette pal = scrollarea->viewport()->property("_q_original_background_palette").value<QPalette>();
scrollarea->viewport()->setPalette(pal);
scrollarea->viewport()->setProperty("_q_original_background_palette", QVariant());
}
+ if (widget->inherits("QAbstractSpinBox")) {
+ const QVariant originalWidth = widget->property(originalWidthProperty.constData());
+ if (originalWidth.isValid()) {
+ widget->resize(originalWidth.toInt(), widget->size().height());
+ widget->setProperty(originalWidthProperty.constData(), QVariant());
+ }
+ }
}
/*