summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp16
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp73
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp3
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.cpp6
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.cpp53
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm8
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm3
-rw-r--r--src/plugins/platforms/cocoa/qnsview_keys.mm3
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h5
-rw-r--r--src/plugins/platforms/ios/qiosdocumentpickercontroller.h5
-rw-r--r--src/plugins/platforms/ios/qiosdocumentpickercontroller.mm13
-rw-r--r--src/plugins/platforms/ios/qiosplatformaccessibility.h2
-rw-r--r--src/plugins/platforms/ios/qiosplatformaccessibility.mm2
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.h5
-rw-r--r--src/plugins/platforms/ios/qioswindow.h5
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.mm5
-rw-r--r--src/plugins/platforms/ios/quiview.h5
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.cpp114
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.h3
-rw-r--r--src/plugins/platforms/wasm/qwasminputcontext.cpp4
-rw-r--r--src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp195
-rw-r--r--src/plugins/platforms/wayland/qwaylandwindow.cpp24
-rw-r--r--src/plugins/platforms/wayland/qwaylandwindow_p.h10
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp6
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp5
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp1
28 files changed, 367 insertions, 214 deletions
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index a1edf49da12..6154f4121d2 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -470,7 +470,6 @@ namespace QtAndroidAccessibility
case QAccessible::Role::Link:
{
if (state.checkable)
- // There is also a android.widget.Switch for which we have no match.
return QStringLiteral("android.widget.ToggleButton");
return QStringLiteral("android.widget.Button");
}
@@ -478,6 +477,8 @@ namespace QtAndroidAccessibility
// As of android/accessibility/utils/Role.java::getRole a CheckBox
// is NOT android.widget.CheckBox
return QStringLiteral("android.widget.CompoundButton");
+ case QAccessible::Role::Switch:
+ return QStringLiteral("android.widget.Switch");
case QAccessible::Role::Clock:
return QStringLiteral("android.widget.TextClock");
case QAccessible::Role::ComboBox:
@@ -725,9 +726,18 @@ namespace QtAndroidAccessibility
break;
}
+ float min = info.minValue.toFloat();
+ float max = info.maxValue.toFloat();
+ float current = info.currentValue.toFloat();
+ if (info.role == QAccessible::ProgressBar) {
+ rangeType = 2; // RANGE_TYPE_PERCENT
+ current = 100 * (current - min) / (max - min);
+ min = 0.0f;
+ max = 100.0f;
+ }
+
QJniObject rangeInfo("android/view/accessibility/AccessibilityNodeInfo$RangeInfo",
- "(IFFF)V", rangeType, info.minValue.toFloat(),
- info.maxValue.toFloat(), info.currentValue.toFloat());
+ "(IFFF)V", rangeType, min, max, current);
if (rangeInfo.isValid()) {
env->CallVoidMethod(node, m_setRangeInfoMethodID, rangeInfo.object());
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 8c5335d9c31..9059fab757b 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -359,20 +359,41 @@ namespace QtAndroid
static bool initJavaReferences(QJniEnvironment &env);
-static void initializeBackends()
+static bool initAndroidQpaPlugin(JNIEnv *jenv, jobject object)
{
+ Q_UNUSED(jenv)
+ Q_UNUSED(object)
+
+ // Init all the Java refs, if they haven't already been initialized. They get initialized
+ // when the library is loaded, but in case Qt is terminated, they are cleared, and in case
+ // Qt is then started again JNI_OnLoad will not be called again, since the library is already
+ // loaded - in that case we need to init again here, hence the check.
+ // TODO QTBUG-130614 QtCore also inits some Java references in qjnihelpers - we probably
+ // want to reset those, too.
+ QJniEnvironment qEnv;
+ if (!qEnv.isValid()) {
+ qCritical() << "Failed to initialize the JNI Environment";
+ return false;
+ }
+
+ if (!initJavaReferences(qEnv))
+ return false;
+
+ m_androidPlatformIntegration = nullptr;
+
// File engine handler instantiation registers the handler
m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler();
m_androidContentFileEngineHandler = new AndroidContentFileEngineHandler();
m_androidApkFileEngineHandler = new QAndroidApkFileEngineHandler();
m_backendRegister = new AndroidBackendRegister();
-}
-static bool initCleanupHandshakeSemaphores()
-{
- return sem_init(&m_exitSemaphore, 0, 0) != -1
- && sem_init(&m_stopQtSemaphore, 0, 0) != -1;
+ if (sem_init(&m_exitSemaphore, 0, 0) == -1 && sem_init(&m_stopQtSemaphore, 0, 0) == -1) {
+ qCritical() << "Failed to init Qt application cleanup semaphores";
+ return false;
+ }
+
+ return true;
}
static void startQtNativeApplication(JNIEnv *jenv, jobject object, jstring paramsString)
@@ -391,23 +412,6 @@ static void startQtNativeApplication(JNIEnv *jenv, jobject object, jstring param
vm->AttachCurrentThread(&env, &args);
}
- // Init all the Java refs, if they haven't already been initialized. They get initialized
- // when the library is loaded, but in case Qt is terminated, they are cleared, and in case
- // Qt is then started again JNI_OnLoad will not be called again, since the library is already
- // loaded - in that case we need to init again here, hence the check.
- // TODO QTBUG-130614 QtCore also inits some Java references in qjnihelpers - we probably
- // want to reset those, too.
- QJniEnvironment qEnv;
- if (!qEnv.isValid()) {
- qCritical() << "Failed to initialize the JNI Environment";
- return;
- }
- if (!initJavaReferences(qEnv))
- return;
-
- m_androidPlatformIntegration = nullptr;
- initializeBackends();
-
const QStringList argsList = QProcess::splitCommand(QJniObject(paramsString).toString());
const int argc = argsList.size();
QVarLengthArray<char *> argv(argc + 1);
@@ -444,11 +448,6 @@ static void startQtNativeApplication(JNIEnv *jenv, jobject object, jstring param
return;
}
- if (!initCleanupHandshakeSemaphores()) {
- qCritical() << "Failed to init Qt application cleanup semaphores";
- return;
- }
-
// Register type for invokeMethod() calls.
qRegisterMetaType<Qt::ScreenOrientation>("Qt::ScreenOrientation");
@@ -458,13 +457,6 @@ static void startQtNativeApplication(JNIEnv *jenv, jobject object, jstring param
startQtAndroidPluginCalled.fetchAndAddRelease(1);
- QtNative::callStaticMethod("setStarted", true);
-
- // The service must wait until the QCoreApplication starts,
- // otherwise onBind will be called too early.
- if (QtAndroidPrivate::service().isValid() && QtAndroid::isQtApplication())
- QtAndroidPrivate::waitForServiceSetup();
-
const int ret = m_main(argc, argv.data());
qInfo() << "main() returned" << ret;
@@ -540,6 +532,15 @@ static void clearJavaReferences(JNIEnv *env)
}
}
+static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/)
+{
+ Q_UNUSED(env);
+ // The service must wait until the QCoreApplication starts otherwise onBind will be
+ // called too early
+ if (QtAndroidPrivate::service().isValid() && QtAndroid::isQtApplication())
+ QtAndroidPrivate::waitForServiceSetup();
+}
+
static void terminateQtNativeApplication(JNIEnv *env, jclass /*clazz*/)
{
// QAndroidEventDispatcherStopper is stopped when the user uses the task manager
@@ -730,8 +731,10 @@ static jobject onBind(JNIEnv */*env*/, jclass /*cls*/, jobject intent)
}
static JNINativeMethod methods[] = {
+ { "initAndroidQpaPlugin", "()Z", (void *)initAndroidQpaPlugin },
{ "startQtNativeApplication", "(Ljava/lang/String;)V", (void *)startQtNativeApplication },
{ "terminateQtNativeApplication", "()V", (void *)terminateQtNativeApplication },
+ { "waitForServiceSetup", "()V", (void *)waitForServiceSetup },
{ "updateApplicationState", "(I)V", (void *)updateApplicationState },
{ "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult },
{ "onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent },
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index ecbbddb2e36..1d755139b46 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -82,9 +82,6 @@ static bool hasValidFocusObject()
if (!m_androidInputContext)
return false;
- if (!m_androidInputContext->isInputPanelVisible())
- return false;
-
const auto focusObject = m_androidInputContext->focusObject();
if (!focusObject)
return false;
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index c8555cdc659..f64742ff133 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -291,7 +291,7 @@ void QAndroidPlatformScreen::topVisibleWindowChanged()
if (w && w->handle()) {
QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle());
if (platformWindow) {
- platformWindow->updateSystemUiVisibility();
+ platformWindow->updateSystemUiVisibility(w->windowStates(), w->flags());
platformWindow->updateFocusedEditText();
}
}
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp
index 822a5357107..0d8673aac03 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.cpp
+++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp
@@ -27,7 +27,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaMenus, "qt.qpa.menus")
-Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
+Q_DECLARE_JNI_CLASS(QtWindowInsetsController, "org/qtproject/qt/android/QtWindowInsetsController")
using namespace Qt::StringLiterals;
@@ -448,9 +448,9 @@ void QAndroidPlatformTheme::requestColorScheme(Qt::ColorScheme scheme)
const auto iface = qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
iface->runOnAndroidMainThread([=]() {
bool isLight = scheme == Qt::ColorScheme::Light;
- QtJniTypes::QtDisplayManager::callStaticMethod("setStatusBarColorHint",
+ QtJniTypes::QtWindowInsetsController::callStaticMethod("setStatusBarColorHint",
iface->context().object<QtJniTypes::Activity>(), isLight);
- QtJniTypes::QtDisplayManager::callStaticMethod("setNavigationBarColorHint",
+ QtJniTypes::QtWindowInsetsController::callStaticMethod("setNavigationBarColorHint",
iface->context().object<QtJniTypes::Activity>(), isLight);
});
}
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp
index 937839ace0c..c4245998772 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp
@@ -22,6 +22,7 @@ Q_DECLARE_JNI_CLASS(QtInputInterface, "org/qtproject/qt/android/QtInputInterface
Q_DECLARE_JNI_CLASS(QtInputConnectionListener,
"org/qtproject/qt/android/QtInputConnection$QtInputConnectionListener")
Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtWindowInterface")
+Q_DECLARE_JNI_CLASS(QtWindowInsetsController, "org/qtproject/qt/android/QtWindowInsetsController")
QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
: QPlatformWindow(window), m_nativeQtWindow(nullptr),
@@ -55,15 +56,12 @@ void QAndroidPlatformWindow::initialize()
isForeignWindow(), m_nativeParentQtWindow, listener);
m_nativeViewId = m_nativeQtWindow.callMethod<jint>("getId");
- m_windowFlags = Qt::Widget;
- m_windowState = Qt::WindowNoState;
// the surfaceType is overwritten in QAndroidPlatformOpenGLWindow ctor so let's save
// the fact that it's a raster window for now
m_isRaster = window->surfaceType() == QSurface::RasterSurface;
- setWindowState(window->windowStates());
// the following is in relation to the virtual geometry
- const bool forceMaximize = m_windowState & (Qt::WindowMaximized | Qt::WindowFullScreen);
+ const bool forceMaximize = window->windowStates() & (Qt::WindowMaximized | Qt::WindowFullScreen);
const QRect nativeScreenGeometry = platformScreen()->availableGeometry();
if (forceMaximize) {
setGeometry(nativeScreenGeometry);
@@ -122,7 +120,7 @@ void QAndroidPlatformWindow::raise()
QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
return;
}
- updateSystemUiVisibility();
+ updateSystemUiVisibility(window()->windowStates(), window()->flags());
platformScreen()->raise(this);
}
@@ -166,13 +164,13 @@ void QAndroidPlatformWindow::setVisible(bool visible)
if (!visible && window() == qGuiApp->focusWindow()) {
platformScreen()->topVisibleWindowChanged();
} else {
- updateSystemUiVisibility();
- if ((m_windowState & Qt::WindowFullScreen)
- || (window()->flags() & Qt::ExpandedClientAreaHint)) {
+ const Qt::WindowStates states = window()->windowStates();
+ const Qt::WindowFlags flags = window()->flags();
+ updateSystemUiVisibility(states, flags);
+ if (states & Qt::WindowFullScreen || flags & Qt::ExpandedClientAreaHint)
setGeometry(platformScreen()->geometry());
- } else if (m_windowState & Qt::WindowMaximized) {
+ else if (states & Qt::WindowMaximized)
setGeometry(platformScreen()->availableGeometry());
- }
requestActivateWindow();
}
}
@@ -187,27 +185,18 @@ void QAndroidPlatformWindow::setVisible(bool visible)
void QAndroidPlatformWindow::setWindowState(Qt::WindowStates state)
{
- if (m_windowState == state)
- return;
-
QPlatformWindow::setWindowState(state);
- m_windowState = state;
if (window()->isVisible())
- updateSystemUiVisibility();
+ updateSystemUiVisibility(state, window()->flags());
}
void QAndroidPlatformWindow::setWindowFlags(Qt::WindowFlags flags)
{
- if (m_windowFlags == flags)
- return;
+ QPlatformWindow::setWindowFlags(flags);
- m_windowFlags = flags;
-}
-
-Qt::WindowFlags QAndroidPlatformWindow::windowFlags() const
-{
- return m_windowFlags;
+ if (window()->isVisible())
+ updateSystemUiVisibility(window()->windowStates(), flags);
}
void QAndroidPlatformWindow::setParent(const QPlatformWindow *window)
@@ -255,15 +244,21 @@ void QAndroidPlatformWindow::requestActivateWindow()
raise();
}
-void QAndroidPlatformWindow::updateSystemUiVisibility()
+void QAndroidPlatformWindow::updateSystemUiVisibility(Qt::WindowStates states, Qt::WindowFlags flags)
{
- const int flags = window()->flags();
const bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
if (!isNonRegularWindow) {
- const bool isFullScreen = (m_windowState & Qt::WindowFullScreen);
- const bool expandedToCutout = (flags & Qt::ExpandedClientAreaHint);
- QtAndroid::backendRegister()->callInterface<QtJniTypes::QtWindowInterface, void>(
- "setSystemUiVisibility", isFullScreen, expandedToCutout);
+ auto iface = qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
+ iface->runOnAndroidMainThread([=]() {
+ using namespace QtJniTypes;
+ auto activity = iface->context().object<Activity>();
+ if (states & Qt::WindowFullScreen)
+ QtWindowInsetsController::callStaticMethod("showFullScreen", activity);
+ else if (flags & Qt::ExpandedClientAreaHint)
+ QtWindowInsetsController::callStaticMethod("showExpanded", activity);
+ else
+ QtWindowInsetsController::callStaticMethod("showNormal", activity);
+ });
}
}
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h
index 07f4e12b35c..826a8d30ade 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformwindow.h
@@ -43,7 +43,6 @@ public:
void setWindowState(Qt::WindowStates state) override;
void setWindowFlags(Qt::WindowFlags flags) override;
- Qt::WindowFlags windowFlags() const;
void setParent(const QPlatformWindow *window) override;
WId winId() const override;
@@ -58,7 +57,7 @@ public:
void propagateSizeHints() override;
void requestActivateWindow() override;
- void updateSystemUiVisibility();
+ void updateSystemUiVisibility(Qt::WindowStates states, Qt::WindowFlags flags);
void updateFocusedEditText();
inline bool isRaster() const { return m_isRaster; }
bool isExposed() const override;
@@ -82,8 +81,6 @@ protected:
bool isEmbeddingContainer() const;
virtual void clearSurface() {}
- Qt::WindowFlags m_windowFlags;
- Qt::WindowStates m_windowState;
bool m_isRaster;
int m_nativeViewId = -1;
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 69ee3638ac6..08c9f5d5ba2 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -132,6 +132,7 @@ static void populateRoleMap()
roleMap[QAccessible::ComboBox] = NSAccessibilityComboBoxRole;
roleMap[QAccessible::RadioButton] = NSAccessibilityRadioButtonRole;
roleMap[QAccessible::CheckBox] = NSAccessibilityCheckBoxRole;
+ roleMap[QAccessible::Switch] = NSAccessibilityCheckBoxRole;
roleMap[QAccessible::StaticText] = NSAccessibilityStaticTextRole;
roleMap[QAccessible::Table] = NSAccessibilityTableRole;
roleMap[QAccessible::StatusBar] = NSAccessibilityStaticTextRole;
@@ -204,6 +205,8 @@ NSString *macSubrole(QAccessibleInterface *interface)
return NSAccessibilitySecureTextFieldSubrole;
if (interface->role() == QAccessible::PageTab)
return NSAccessibilityTabButtonSubrole;
+ if (interface->role() == QAccessible::Switch)
+ return NSAccessibilitySwitchSubrole;
return nil;
}
@@ -328,8 +331,11 @@ NSString *getTranslatedAction(const QString &qtAction)
QString translateAction(NSString *nsAction, QAccessibleInterface *interface)
{
if ([nsAction compare: NSAccessibilityPressAction] == NSOrderedSame) {
- if (interface->role() == QAccessible::CheckBox || interface->role() == QAccessible::RadioButton)
+ if (interface->role() == QAccessible::CheckBox
+ || interface->role() == QAccessible::RadioButton
+ || interface->role() == QAccessible::Switch) {
return QAccessibleActionInterface::toggleAction();
+ }
return QAccessibleActionInterface::pressAction();
} else if ([nsAction compare: NSAccessibilityIncrementAction] == NSOrderedSame)
return QAccessibleActionInterface::increaseAction();
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index d4c5d0f0425..e0ef6cec794 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -161,7 +161,8 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
bool selectable = (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
|| [self panel:m_panel shouldEnableURL:url];
- m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
+ if (!openpanel_cast(m_panel))
+ m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
[self updateProperties];
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm
index aab01a7b439..e9ef769ec4b 100644
--- a/src/plugins/platforms/cocoa/qnsview_keys.mm
+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm
@@ -114,6 +114,9 @@ static bool sendAsShortcut(const KeyEvent &keyEvent, QWindow *window)
qCDebug(lcQpaKeys) << "Interpreting key event for focus object" << focusObject;
m_currentlyInterpretedKeyEvent = nsevent;
+ // Asking the input context to handle the event will involve both
+ // the current input method, as well as NSKeyBindingManager, which
+ // may result in action callbacks to doCommandBySelector.
if (![self.inputContext handleEvent:nsevent]) {
qCDebug(lcQpaKeys) << "Input context did not consume event";
m_sendKeyEvent = true;
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
index 60b9bc8fc02..8fdcf88293e 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
+#ifndef QIOSIMAGEPICKERCONTROLLER_H
+#define QIOSIMAGEPICKERCONTROLLER_H
+
#import <UIKit/UIKit.h>
#include "../../qiosfiledialog.h"
@@ -9,3 +12,5 @@
@interface QIOSImagePickerController : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog;
@end
+
+#endif // QIOSIMAGEPICKERCONTROLLER_H
diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.h b/src/plugins/platforms/ios/qiosdocumentpickercontroller.h
index 289c3ee3258..a227312c5b0 100644
--- a/src/plugins/platforms/ios/qiosdocumentpickercontroller.h
+++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.h
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
+#ifndef QIOSDOCUMENTPICKERCONTROLLER_H
+#define QIOSDOCUMENTPICKERCONTROLLER_H
+
#import <UIKit/UIKit.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
@@ -12,3 +15,5 @@
UIAdaptivePresentationControllerDelegate>
- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog;
@end
+
+#endif // QIOSDOCUMENTPICKERCONTROLLER_H
diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
index 4e019b69cc4..6ca6554f673 100644
--- a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
+++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
@@ -7,8 +7,10 @@
#include "qiosdocumentpickercontroller.h"
+#include <QtCore/qpointer.h>
+
@implementation QIOSDocumentPickerController {
- QIOSFileDialog *m_fileDialog;
+ QPointer<QIOSFileDialog> m_fileDialog;
}
- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog
@@ -61,6 +63,9 @@
{
Q_UNUSED(controller);
+ if (!m_fileDialog)
+ return;
+
QList<QUrl> files;
for (NSURL* url in urls)
files.append(QUrl::fromNSURL(url));
@@ -71,12 +76,18 @@
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
{
+ if (!m_fileDialog)
+ return;
+
Q_UNUSED(controller);
emit m_fileDialog->reject();
}
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
{
+ if (!m_fileDialog)
+ return;
+
Q_UNUSED(presentationController);
// "Called on the delegate when the user has taken action to dismiss the
diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.h b/src/plugins/platforms/ios/qiosplatformaccessibility.h
index 04cddf00f4e..1ccc5bd089a 100644
--- a/src/plugins/platforms/ios/qiosplatformaccessibility.h
+++ b/src/plugins/platforms/ios/qiosplatformaccessibility.h
@@ -23,7 +23,7 @@ public:
private:
QMacNotificationObserver m_focusObserver;
- QMacAccessibilityElement *m_focusElement;
+ QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *m_focusElement;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm
index 26f48468c45..a63c75757e4 100644
--- a/src/plugins/platforms/ios/qiosplatformaccessibility.mm
+++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm
@@ -12,6 +12,8 @@
#include "qioswindow.h"
#include "quiaccessibilityelement.h"
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
+
QIOSPlatformAccessibility::QIOSPlatformAccessibility()
{
m_focusObserver = QMacNotificationObserver(
diff --git a/src/plugins/platforms/ios/qiostextresponder.h b/src/plugins/platforms/ios/qiostextresponder.h
index addfae3d748..7d73ed9821a 100644
--- a/src/plugins/platforms/ios/qiostextresponder.h
+++ b/src/plugins/platforms/ios/qiostextresponder.h
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
+#ifndef QIOSTEXTRESPONDER_H
+#define QIOSTEXTRESPONDER_H
+
#import <UIKit/UIKit.h>
#include <QtCore/qstring.h>
@@ -50,3 +53,5 @@ QT_END_NAMESPACE
@property(nonatomic, assign) id<UITextInputDelegate> inputDelegate;
@end
+
+#endif // QIOSTEXTRESPONDER_H
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index 23a4c506c24..5024013ba77 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -10,9 +10,6 @@
#import <UIKit/UIKit.h>
-class QIOSContext;
-class QIOSWindow;
-
@class QUIView;
QT_BEGIN_NAMESPACE
@@ -84,7 +81,7 @@ private:
QDebug operator<<(QDebug debug, const QIOSWindow *window);
#endif
-QT_MANGLE_NAMESPACE(QUIView) *quiview_cast(UIView *view);
+QUIView *quiview_cast(UIView *view);
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm
index d10fe40840a..0d6952bddf0 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.mm
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm
@@ -115,6 +115,9 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
|| iface->role() == QAccessible::RadioButton)
return @"";
+ if (iface->role() == QAccessible::Switch)
+ return state.checked ? @"1" : @"0";
+
return state.checked
? QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_CHECKED).toNSString()
: QCoreApplication::translate(ACCESSIBILITY_ELEMENT, AE_UNCHECKED).toNSString();
@@ -169,6 +172,8 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
|| accessibleRole == QAccessible::RadioButton) {
if (state.checked)
traits |= UIAccessibilityTraitSelected;
+ } else if (accessibleRole == QAccessible::Switch) {
+ traits |= UIAccessibilityTraitToggleButton;
} else if (accessibleRole == QAccessible::EditableText) {
static auto defaultTextFieldTraits = []{
auto *textField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease];
diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h
index 84726216021..12ae3646ad9 100644
--- a/src/plugins/platforms/ios/quiview.h
+++ b/src/plugins/platforms/ios/quiview.h
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
+#ifndef QUIVIEW_H
+#define QUIVIEW_H
+
#import <UIKit/UIKit.h>
#include <qhash.h>
@@ -39,3 +42,5 @@ QT_END_NAMESPACE
@interface QUIMetalView : QUIView
@end
#endif
+
+#endif // QUIVIEW_H
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
index 1cf81453fe7..5fa79482217 100644
--- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
@@ -323,8 +323,9 @@ void QWasmAccessibility::setProperty(emscripten::val element, const std::string
}
-void QWasmAccessibility::addEventListener(emscripten::val element, const char *eventType)
+void QWasmAccessibility::addEventListener(QAccessibleInterface *iface, emscripten::val element, const char *eventType)
{
+ element.set("data-qta11yinterface", reinterpret_cast<size_t>(iface));
element.call<void>("addEventListener", emscripten::val(eventType),
QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex),
true);
@@ -352,7 +353,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
case QAccessible::Button: {
element = document.call<emscripten::val>("createElement", std::string("button"));
- addEventListener(element, "click");
+ addEventListener(iface, element, "click");
} break;
case QAccessible::CheckBox: {
@@ -360,7 +361,18 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
setAttribute(element, "type", "checkbox");
setAttribute(element, "checked", iface->state().checked);
setProperty(element, "indeterminate", iface->state().checkStateMixed);
- addEventListener(element, "change");
+ addEventListener(iface, element, "change");
+ } break;
+
+ case QAccessible::Switch: {
+ element = document.call<emscripten::val>("createElement", std::string("button"));
+ setAttribute(element, "type", "button");
+ setAttribute(element, "role", "switch");
+ if (iface->state().checked)
+ setAttribute(element, "aria-checked", "true");
+ else
+ setAttribute(element, "aria-checked", "false");
+ addEventListener(iface, element, "change");
} break;
case QAccessible::RadioButton: {
@@ -368,7 +380,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
setAttribute(element, "type", "radio");
setAttribute(element, "checked", iface->state().checked);
setProperty(element, "name", "buttonGroup");
- addEventListener(element, "change");
+ addEventListener(iface, element, "change");
} break;
case QAccessible::SpinBox:
@@ -402,7 +414,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
element = document.call<emscripten::val>("createElement", std::string("button"));
setAttribute(element, "role", "tab");
setAttribute(element, "title", text.toStdString());
- addEventListener(element, "click");
+ addEventListener(iface, element, "click");
} break;
case QAccessible::ScrollBar: {
@@ -411,7 +423,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
element = document.call<emscripten::val>("createElement", std::string("div"));
setAttribute(element, "role", "scrollbar");
setAttribute(element, "aria-valuenow", valueString);
- addEventListener(element, "change");
+ addEventListener(iface, element, "change");
} break;
case QAccessible::StaticText: {
@@ -425,7 +437,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
element = document.call<emscripten::val>("createElement", std::string("div"));
setAttribute(element, "role", "toolbar");
setAttribute(element, "title", text.toStdString());
- addEventListener(element, "click");
+ addEventListener(iface, element, "click");
}break;
case QAccessible::MenuItem:
case QAccessible::ButtonMenu: {
@@ -433,7 +445,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
element = document.call<emscripten::val>("createElement", std::string("button"));
setAttribute(element, "role", "menuitem");
setAttribute(element, "title", text.toStdString());
- addEventListener(element, "click");
+ addEventListener(iface, element, "click");
}break;
case QAccessible::MenuBar:
case QAccessible::PopupMenu: {
@@ -460,7 +472,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
element = document.call<emscripten::val>("createElement", std::string("div"));
}
- addEventListener(element, "focus");
+ addEventListener(iface, element, "focus");
return element;
}();
@@ -531,6 +543,7 @@ void QWasmAccessibility::linkToParent(QAccessibleInterface *iface)
{
emscripten::val element = getHtmlElement(iface);
emscripten::val container = getElementContainer(iface);
+
if (container.isUndefined() || element.isUndefined())
return;
@@ -543,21 +556,21 @@ void QWasmAccessibility::linkToParent(QAccessibleInterface *iface)
emscripten::val next = emscripten::val::undefined();
const int thisIndex = iface->parent()->indexOfChild(iface);
- Q_ASSERT(thisIndex >= 0 && thisIndex < iface->parent()->childCount());
- for (int i = thisIndex + 1; i < iface->parent()->childCount(); ++i) {
- const auto elementI = getHtmlElement(iface->parent()->child(i));
- if (!elementI.isUndefined() &&
- elementI["parentElement"] == container) {
- next = elementI;
- break;
+ if (thisIndex >= 0) {
+ Q_ASSERT(thisIndex < iface->parent()->childCount());
+ for (int i = thisIndex + 1; i < iface->parent()->childCount(); ++i) {
+ const auto elementI = getHtmlElement(iface->parent()->child(i));
+ if (!elementI.isUndefined() &&
+ elementI["parentElement"] == container) {
+ next = elementI;
+ break;
+ }
}
+ if (next.isUndefined())
+ container.call<void>("appendChild", element);
+ else
+ container.call<void>("insertBefore", element, next);
}
- if (next.isUndefined()) {
- container.call<void>("appendChild", element);
- } else {
- container.call<void>("insertBefore", element, next);
- }
-
const auto activeElementAfter = emscripten::val::take_ownership(
getActiveElement_js(emscripten::val::undefined().as_handle()));
if (activeElementBefore != activeElementAfter) {
@@ -701,22 +714,26 @@ void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event)
void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event)
{
- QAccessibleInterface *iface = m_elements.key(event["target"]);
+ if (event["target"].isNull() || event["target"].isUndefined())
+ return;
- if (iface == nullptr) {
+ if (event["target"]["data-qta11yinterface"].isNull() || event["target"]["data-qta11yinterface"].isUndefined())
return;
- } else {
- QString eventType = QString::fromStdString(event["type"].as<std::string>());
- const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
-
- if (eventType == "focus") {
- if (actionNames.contains(QAccessibleActionInterface::setFocusAction()))
- iface->actionInterface()->doAction(QAccessibleActionInterface::setFocusAction());
- } else if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
- iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
- } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) {
- iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction());
- }
+
+ auto iface = reinterpret_cast<QAccessibleInterface *>(event["target"]["data-qta11yinterface"].as<size_t>());
+ if (m_elements.find(iface) == m_elements.end())
+ return;
+
+ const QString eventType = QString::fromStdString(event["type"].as<std::string>());
+ const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
+
+ if (eventType == "focus") {
+ if (actionNames.contains(QAccessibleActionInterface::setFocusAction()))
+ iface->actionInterface()->doAction(QAccessibleActionInterface::setFocusAction());
+ } else if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
+ iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
+ } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) {
+ iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction());
}
}
@@ -743,6 +760,28 @@ void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event)
break;
}
}
+
+void QWasmAccessibility::handleSwitchUpdate(QAccessibleEvent *event)
+{
+ switch (event->type()) {
+ case QAccessible::Focus:
+ case QAccessible::NameChanged: {
+ setHtmlElementTextName(event->accessibleInterface());
+ } break;
+ case QAccessible::StateChanged: {
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ const emscripten::val element = getHtmlElement(accessible);
+ if (accessible->state().checked)
+ setAttribute(element, "aria-checked", "true");
+ else
+ setAttribute(element, "aria-checked", "false");
+ } break;
+ default:
+ qCDebug(lcQpaAccessibility) << "TODO: implement handleSwitchUpdate for event" << event->type();
+ break;
+ }
+}
+
void QWasmAccessibility::handleToolUpdate(QAccessibleEvent *event)
{
QAccessibleInterface *iface = event->accessibleInterface();
@@ -1152,6 +1191,9 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
case QAccessible::CheckBox:
handleCheckBoxUpdate(event);
break;
+ case QAccessible::Switch:
+ handleSwitchUpdate(event);
+ break;
case QAccessible::EditableText:
handleLineEditUpdate(event);
break;
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.h b/src/plugins/platforms/wasm/qwasmaccessibility.h
index ee2be18e5b7..26f3e0e9afe 100644
--- a/src/plugins/platforms/wasm/qwasmaccessibility.h
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.h
@@ -81,6 +81,7 @@ private:
void handleStaticTextUpdate(QAccessibleEvent *event);
void handleButtonUpdate(QAccessibleEvent *event);
void handleCheckBoxUpdate(QAccessibleEvent *event);
+ void handleSwitchUpdate(QAccessibleEvent *event);
void handleDialogUpdate(QAccessibleEvent *event);
void handleMenuUpdate(QAccessibleEvent *event);
void handleToolUpdate(QAccessibleEvent *event);
@@ -115,7 +116,7 @@ private:
void setProperty(emscripten::val element, const std::string &attr, const char *val);
void setProperty(emscripten::val element, const std::string &attr, bool val);
- void addEventListener(emscripten::val element, const char *eventType);
+ void addEventListener(QAccessibleInterface *, emscripten::val element, const char *eventType);
private:
static QWasmAccessibility *s_instance;
diff --git a/src/plugins/platforms/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp
index 614d5bd25a3..18a457198f1 100644
--- a/src/plugins/platforms/wasm/qwasminputcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp
@@ -225,8 +225,8 @@ void QWasmInputContext::updateGeometry()
qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "propagating inputItemRectangle:" << inputItemRectangle;
m_inputElement["style"].set("left", std::to_string(inputItemRectangle.x()) + "px");
m_inputElement["style"].set("top", std::to_string(inputItemRectangle.y()) + "px");
- m_inputElement["style"].set("width", std::to_string(inputItemRectangle.width()) + "px");
- m_inputElement["style"].set("height", std::to_string(inputItemRectangle.height()) + "px");
+ m_inputElement["style"].set("width", "1px");
+ m_inputElement["style"].set("height", "1px");
}
}
diff --git a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
index a1a173f0182..17422bd606d 100644
--- a/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
+++ b/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp
@@ -201,7 +201,7 @@ void QWaylandXdgSurface::Toplevel::requestWindowFlags(Qt::WindowFlags flags)
delete m_decoration;
m_decoration = nullptr;
} else {
- m_decoration->unsetMode();
+ m_decoration->requestMode(QWaylandXdgToplevelDecorationV1::mode_server_side);
}
}
}
@@ -697,108 +697,135 @@ void QWaylandXdgSurface::setWindowPosition(const QPoint &position)
window()->updateExposure();
}
+static QtWayland::xdg_positioner::gravity gravityFromEdge(Qt::Edges edges)
+{
+ switch (edges) {
+ case Qt::Edges():
+ return QtWayland::xdg_positioner::gravity_none;
+ case Qt::TopEdge:
+ return QtWayland::xdg_positioner::gravity_top;
+ case Qt::TopEdge | Qt::RightEdge:
+ return QtWayland::xdg_positioner::gravity_top_right;
+ case Qt::RightEdge:
+ return QtWayland::xdg_positioner::gravity_right;
+ case Qt::BottomEdge | Qt::RightEdge:
+ return QtWayland::xdg_positioner::gravity_bottom_right;
+ case Qt::BottomEdge:
+ return QtWayland::xdg_positioner::gravity_bottom;
+ case Qt::BottomEdge | Qt::LeftEdge:
+ return QtWayland::xdg_positioner::gravity_bottom_left;
+ case Qt::LeftEdge:
+ return QtWayland::xdg_positioner::gravity_left;
+ case Qt::TopEdge | Qt::LeftEdge:
+ return QtWayland::xdg_positioner::gravity_top_left;
+ }
+ qCWarning(lcQpaWayland) << "Cannot map positioner gravity " << edges;
+ return QtWayland::xdg_positioner::gravity_none;
+}
+
+static QtWayland::xdg_positioner::anchor anchorFromEdge(Qt::Edges edges)
+{
+ switch (edges) {
+ case Qt::Edges():
+ return QtWayland::xdg_positioner::anchor_none;
+ case Qt::TopEdge:
+ return QtWayland::xdg_positioner::anchor_top;
+ case Qt::TopEdge | Qt::RightEdge:
+ return QtWayland::xdg_positioner::anchor_top_right;
+ case Qt::RightEdge:
+ return QtWayland::xdg_positioner::anchor_right;
+ case Qt::BottomEdge | Qt::RightEdge:
+ return QtWayland::xdg_positioner::anchor_bottom_right;
+ case Qt::BottomEdge:
+ return QtWayland::xdg_positioner::anchor_bottom;
+ case Qt::BottomEdge | Qt::LeftEdge:
+ return QtWayland::xdg_positioner::anchor_bottom_left;
+ case Qt::LeftEdge:
+ return QtWayland::xdg_positioner::anchor_left;
+ case Qt::TopEdge | Qt::LeftEdge:
+ return QtWayland::xdg_positioner::anchor_top_left;
+ }
+ qCWarning(lcQpaWayland) << "Cannot map positioner anchor" << edges;
+ return QtWayland::xdg_positioner::anchor_none;
+}
+
std::unique_ptr<QWaylandXdgSurface::Positioner> QWaylandXdgSurface::createPositioner(QWaylandWindow *parent)
{
std::unique_ptr<Positioner> positioner(new Positioner(m_shell));
- // set_popup expects a position relative to the parent
- QRect windowGeometry = m_window->windowContentGeometry();
- QMargins windowMargins = m_window->windowContentMargins() - m_window->clientSideMargins();
- QMargins parentMargins = parent->windowContentMargins() - parent->clientSideMargins();
- // These property overrides may be removed when public API becomes available
- QRect placementAnchor = m_window->window()->property("_q_waylandPopupAnchorRect").toRect();
- if (!placementAnchor.isValid()) {
- placementAnchor = QRect(m_window->geometry().topLeft() - parent->geometry().topLeft(), QSize(1,1));
- }
- placementAnchor.translate(windowMargins.left(), windowMargins.top());
- placementAnchor.translate(-parentMargins.left(), -parentMargins.top());
+ // Default case, map the guessed global position to a relative position
+ QRect placementAnchor = QRect(m_window->geometry().topLeft() - parent->geometry().topLeft(), QSize(1,1));
+ Qt::Edges anchor = Qt::TopEdge | Qt::RightEdge;
+ Qt::Edges gravity = Qt::BottomEdge | Qt::RightEdge;
+ uint32_t constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_slide_x | QtWayland::xdg_positioner::constraint_adjustment_slide_y;
- uint32_t anchor = QtWayland::xdg_positioner::anchor_top_left;
+ // Override from window type
+ if (m_window->parentControlGeometry().isValid())
+ placementAnchor = m_window->parentControlGeometry();
+
+ switch (m_window->extendedWindowType()) {
+ case QNativeInterface::Private::QWaylandWindow::Menu:
+ case QNativeInterface::Private::QWaylandWindow::WindowType::ComboBox:
+ anchor = Qt::BottomEdge | Qt::LeftEdge;
+ gravity = Qt::BottomEdge | Qt::RightEdge;
+ constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_slide_x |
+ QtWayland::xdg_positioner::constraint_adjustment_flip_y | QtWayland::xdg_positioner::constraint_adjustment_slide_y;
+ break;
+ case QNativeInterface::Private::QWaylandWindow::SubMenu:
+ anchor = Qt::TopEdge | Qt::RightEdge;
+ gravity = Qt::BottomEdge | Qt::RightEdge;
+ constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_flip_x |
+ QtWayland::xdg_positioner::constraint_adjustment_slide_y;
+ break;
+ case QNativeInterface::Private::QWaylandWindow::ToolTip:
+ anchor = Qt::BottomEdge | Qt::RightEdge;
+ gravity = Qt::BottomEdge | Qt::RightEdge;
+ constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_flip_x | QtWayland::xdg_positioner::constraint_adjustment_slide_x |
+ QtWayland::xdg_positioner::constraint_adjustment_flip_y | QtWayland::xdg_positioner::constraint_adjustment_slide_y;
+ break;
+ default:
+ break;
+ }
+
+ if (qApp->layoutDirection() == Qt::RightToLeft) {
+ if (anchor & (Qt::RightEdge | Qt::LeftEdge))
+ anchor ^= (Qt::RightEdge | Qt::LeftEdge);
+ if (gravity & (Qt::RightEdge | Qt::LeftEdge))
+ gravity ^= (Qt::RightEdge | Qt::LeftEdge);
+ }
+
+ // Override with properties fauxAPI
+ const QVariant placementAnchorVariant = m_window->window()->property("_q_waylandPopupAnchorRect");
+ if (placementAnchorVariant.isValid())
+ placementAnchor = placementAnchorVariant.toRect();
const QVariant anchorVariant = m_window->window()->property("_q_waylandPopupAnchor");
- if (anchorVariant.isValid()) {
- switch (anchorVariant.value<Qt::Edges>()) {
- case Qt::Edges():
- anchor = QtWayland::xdg_positioner::anchor_none;
- break;
- case Qt::TopEdge:
- anchor = QtWayland::xdg_positioner::anchor_top;
- break;
- case Qt::TopEdge | Qt::RightEdge:
- anchor = QtWayland::xdg_positioner::anchor_top_right;
- break;
- case Qt::RightEdge:
- anchor = QtWayland::xdg_positioner::anchor_right;
- break;
- case Qt::BottomEdge | Qt::RightEdge:
- anchor = QtWayland::xdg_positioner::anchor_bottom_right;
- break;
- case Qt::BottomEdge:
- anchor = QtWayland::xdg_positioner::anchor_bottom;
- break;
- case Qt::BottomEdge | Qt::LeftEdge:
- anchor = QtWayland::xdg_positioner::anchor_bottom_left;
- break;
- case Qt::LeftEdge:
- anchor = QtWayland::xdg_positioner::anchor_left;
- break;
- case Qt::TopEdge | Qt::LeftEdge:
- anchor = QtWayland::xdg_positioner::anchor_top_left;
- break;
- }
- }
-
- uint32_t gravity = QtWayland::xdg_positioner::gravity_bottom_right;
+ if (anchorVariant.isValid())
+ anchor = anchorVariant.value<Qt::Edges>();
const QVariant popupGravityVariant = m_window->window()->property("_q_waylandPopupGravity");
- if (popupGravityVariant.isValid()) {
- switch (popupGravityVariant.value<Qt::Edges>()) {
- case Qt::Edges():
- gravity = QtWayland::xdg_positioner::gravity_none;
- break;
- case Qt::TopEdge:
- gravity = QtWayland::xdg_positioner::gravity_top;
- break;
- case Qt::TopEdge | Qt::RightEdge:
- gravity = QtWayland::xdg_positioner::gravity_top_right;
- break;
- case Qt::RightEdge:
- gravity = QtWayland::xdg_positioner::gravity_right;
- break;
- case Qt::BottomEdge | Qt::RightEdge:
- gravity = QtWayland::xdg_positioner::gravity_bottom_right;
- break;
- case Qt::BottomEdge:
- gravity = QtWayland::xdg_positioner::gravity_bottom;
- break;
- case Qt::BottomEdge | Qt::LeftEdge:
- gravity = QtWayland::xdg_positioner::gravity_bottom_left;
- break;
- case Qt::LeftEdge:
- gravity = QtWayland::xdg_positioner::gravity_left;
- break;
- case Qt::TopEdge | Qt::LeftEdge:
- gravity = QtWayland::xdg_positioner::gravity_top_left;
- break;
- }
- }
-
- uint32_t constraintAdjustment = QtWayland::xdg_positioner::constraint_adjustment_slide_x | QtWayland::xdg_positioner::constraint_adjustment_slide_y;
+ if (popupGravityVariant.isValid())
+ gravity = popupGravityVariant.value<Qt::Edges>();
const QVariant constraintAdjustmentVariant = m_window->window()->property("_q_waylandPopupConstraintAdjustment");
- if (constraintAdjustmentVariant.isValid()) {
+ if (constraintAdjustmentVariant.isValid())
constraintAdjustment = constraintAdjustmentVariant.toUInt();
- }
+
+ // set_popup expects a position relative to the parent
+ QRect windowGeometry = m_window->windowContentGeometry();
+ QMargins windowMargins = m_window->windowContentMargins() - m_window->clientSideMargins();
+ QMargins parentMargins = parent->windowContentMargins() - parent->clientSideMargins();
+ placementAnchor.translate(windowMargins.left(), windowMargins.top());
+ placementAnchor.translate(-parentMargins.left(), -parentMargins.top());
positioner->set_anchor_rect(placementAnchor.x(),
placementAnchor.y(),
placementAnchor.width(),
placementAnchor.height());
- positioner->set_anchor(anchor);
- positioner->set_gravity(gravity);
+ positioner->set_anchor(anchorFromEdge(anchor));
+ positioner->set_gravity(gravityFromEdge(gravity));
positioner->set_size(windowGeometry.width(), windowGeometry.height());
positioner->set_constraint_adjustment(constraintAdjustment);
return positioner;
}
-
void QWaylandXdgSurface::setIcon(const QIcon &icon)
{
if (!m_shell->m_topLevelIconManager || !m_toplevel)
diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp
index 7c300843518..be527b08f4d 100644
--- a/src/plugins/platforms/wayland/qwaylandwindow.cpp
+++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp
@@ -481,8 +481,9 @@ void QWaylandWindow::setGeometry(const QRect &r)
if (mShellSurface && !mInResizeFromApplyConfigure) {
const QRect frameGeometry = r.marginsAdded(clientSideMargins()).marginsRemoved(windowContentMargins());
- if (qt_window_private(window())->positionAutomatic)
+ if (qt_window_private(window())->positionAutomatic || m_popupInfo.parentControlGeometry.isValid())
mShellSurface->setWindowSize(frameGeometry.size());
+
else
mShellSurface->setWindowGeometry(frameGeometry);
}
@@ -1945,6 +1946,27 @@ QString QWaylandWindow::sessionRestoreId() const
return mSessionRestoreId;
}
+void QWaylandWindow::setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::WindowType windowType) {
+ m_popupInfo.extendedWindowType = windowType;
+}
+
+QNativeInterface::Private::QWaylandWindow::WindowType QWaylandWindow::extendedWindowType() const
+{
+ return m_popupInfo.extendedWindowType;
+}
+
+void QWaylandWindow::setParentControlGeometry(const QRect &parentControlGeometry) {
+ m_popupInfo.parentControlGeometry = parentControlGeometry;
+ if (mExposed) {
+ mShellSurface->setWindowPosition(window()->position());
+ }
+}
+
+QRect QWaylandWindow::parentControlGeometry() const
+{
+ return m_popupInfo.parentControlGeometry;
+}
+
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wayland/qwaylandwindow_p.h b/src/plugins/platforms/wayland/qwaylandwindow_p.h
index 854724daf82..d6b24d0569f 100644
--- a/src/plugins/platforms/wayland/qwaylandwindow_p.h
+++ b/src/plugins/platforms/wayland/qwaylandwindow_p.h
@@ -255,6 +255,11 @@ public:
void setSessionRestoreId(const QString &role) override;
QString sessionRestoreId() const;
+ void setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::WindowType) override;
+ QNativeInterface::Private::QWaylandWindow::WindowType extendedWindowType() const;
+ void setParentControlGeometry(const QRect &parentAnchor) override;
+ QRect parentControlGeometry() const;
+
public Q_SLOTS:
void applyConfigure();
@@ -397,6 +402,11 @@ private:
void handleFrameCallback(struct ::wl_callback* callback);
const QPlatformWindow *lastParent = nullptr;
+ struct {
+ QRect parentControlGeometry;
+ QNativeInterface::Private::QWaylandWindow::WindowType extendedWindowType = QNativeInterface::Private::QWaylandWindow::Default;
+ } m_popupInfo;
+
static QWaylandWindow *mMouseGrab;
static QWaylandWindow *mTopPopup;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 82a86d6ff3a..01716fba60c 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -4019,9 +4019,11 @@ void QWindowsWindow::requestUpdate()
// request or we are waiting for the event loop to process
// the Posted event on the GUI thread.
if (m_vsyncUpdatePending.testAndSetAcquire(UpdateState::Requested, UpdateState::Posted)) {
- QMetaObject::invokeMethod(w, [w] {
+ QWindowsWindow *oldSelf = this;
+ QMetaObject::invokeMethod(w, [w, oldSelf] {
+ // 'oldSelf' is only used for comparison, don't access it directly!
auto *self = static_cast<QWindowsWindow *>(w->handle());
- if (self) {
+ if (self && self == oldSelf) {
// The platform window is still alive
self->m_vsyncUpdatePending.storeRelease(UpdateState::Ready);
self->deliverUpdateRequest();
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index fc0e053f396..0144786ce5e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -82,8 +82,9 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
if (event->changedStates().checked || event->changedStates().checkStateMixed) {
- // Notifies states changes in checkboxes.
- if (accessible->role() == QAccessible::CheckBox) {
+ // Notifies states changes in checkboxes and switches.
+ if (accessible->role() == QAccessible::CheckBox
+ || accessible->role() == QAccessible::Switch) {
if (auto provider = providerForAccessible(accessible)) {
long toggleState = ToggleState_Off;
if (accessible->state().checked)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
index 4146a56b226..b2675d5b884 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
@@ -132,6 +132,7 @@ long roleToControlTypeId(QAccessible::Role role)
{QAccessible::EditableText, UIA_EditControlTypeId},
{QAccessible::Button, UIA_ButtonControlTypeId},
{QAccessible::CheckBox, UIA_CheckBoxControlTypeId},
+ {QAccessible::Switch, UIA_ButtonControlTypeId},
{QAccessible::RadioButton, UIA_RadioButtonControlTypeId},
{QAccessible::ComboBox, UIA_ComboBoxControlTypeId},
{QAccessible::ProgressBar, UIA_ProgressBarControlTypeId},